diff --git a/app/src/main/java/org/thoughtcrime/securesms/MessageDetailsActivity.java b/app/src/main/java/org/thoughtcrime/securesms/MessageDetailsActivity.java index 79ee15c8a7..5789d6f791 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/MessageDetailsActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/MessageDetailsActivity.java @@ -38,11 +38,12 @@ import androidx.loader.content.Loader; import org.session.libsession.messaging.messages.visible.LinkPreview; +import org.session.libsession.messaging.messages.visible.OpenGroupInvitation; import org.session.libsession.messaging.messages.visible.Quote; import org.session.libsession.messaging.messages.visible.VisibleMessage; import org.session.libsession.messaging.open_groups.OpenGroup; import org.session.libsession.messaging.sending_receiving.MessageSender; -import org.session.libsession.messaging.sending_receiving.attachments.Attachment; +import org.session.libsession.messaging.utilities.UpdateMessageData; import org.thoughtcrime.securesms.MessageDetailsRecipientAdapter.RecipientDeliveryStatus; import org.session.libsession.utilities.color.MaterialColor; import org.thoughtcrime.securesms.conversation.ConversationItem; @@ -448,7 +449,18 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity Recipient recipient = messageRecord.getRecipient(); VisibleMessage message = new VisibleMessage(); message.setId(messageRecord.getId()); - message.setText(messageRecord.getBody()); + if (messageRecord.isOpenGroupInvitation()) { + OpenGroupInvitation openGroupInvitation = new OpenGroupInvitation(); + UpdateMessageData updateMessageData = UpdateMessageData.Companion.fromJSON(messageRecord.getBody()); + if (updateMessageData.getKind() instanceof UpdateMessageData.Kind.OpenGroupInvitation) { + UpdateMessageData.Kind.OpenGroupInvitation data = (UpdateMessageData.Kind.OpenGroupInvitation)updateMessageData.getKind(); + openGroupInvitation.setName(data.getGroupName()); + openGroupInvitation.setUrl(data.getGroupUrl()); + } + message.setOpenGroupInvitation(openGroupInvitation); + } else { + message.setText(messageRecord.getBody()); + } message.setSentTimestamp(messageRecord.getTimestamp()); if (recipient.isGroupRecipient()) { message.setGroupPublicKey(recipient.getAddress().toGroupString()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 9d9875977e..8143b5df5f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -88,6 +88,7 @@ import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate; import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage; import org.session.libsession.messaging.messages.signal.OutgoingSecureMediaMessage; import org.session.libsession.messaging.messages.signal.OutgoingTextMessage; +import org.session.libsession.messaging.messages.visible.OpenGroupInvitation; import org.session.libsession.messaging.messages.visible.VisibleMessage; import org.session.libsession.messaging.open_groups.OpenGroup; import org.session.libsession.messaging.open_groups.OpenGroupV2; @@ -157,6 +158,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil; import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel; import org.thoughtcrime.securesms.loki.activities.EditClosedGroupActivity; import org.thoughtcrime.securesms.loki.activities.HomeActivity; +import org.thoughtcrime.securesms.loki.activities.SelectContactsActivity; import org.thoughtcrime.securesms.loki.api.PublicChatInfoUpdateWorker; import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase; import org.thoughtcrime.securesms.loki.database.LokiUserDatabase; @@ -249,11 +251,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity private static final int PICK_GIF = 10; private static final int SMS_DEFAULT = 11; private static final int MEDIA_SENDER = 12; + private static final int INVITE_CONTACTS = 124; private GlideRequests glideRequests; protected ComposeText composeText; private AnimatingToggle buttonToggle; - private ImageButton sendButton; + private ImageButton sendButton; private ImageButton attachButton; private ProfilePictureView profilePictureView; private TextView titleTextView; @@ -598,6 +601,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity }); break; + case INVITE_CONTACTS: + if (data.getExtras() == null || !data.hasExtra(SelectContactsActivity.Companion.getSelectedContactsKey())) return; + String[] selectedContacts = data.getExtras().getStringArray(SelectContactsActivity.Companion.getSelectedContactsKey()); + sendOpenGroupInvitations(selectedContacts); + break; } } @@ -660,6 +668,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } else if (isActiveGroup()) { inflater.inflate(R.menu.conversation_push_group_options, menu); } + } else if (isOpenGroupOrRSSFeed) { + inflater.inflate(R.menu.conversation_invite_open_group, menu); } inflater.inflate(R.menu.conversation, menu); @@ -768,6 +778,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity // case R.id.menu_conversation_settings: handleConversationSettings(); return true; case R.id.menu_expiring_messages_off: case R.id.menu_expiring_messages: handleSelectMessageExpiration(); return true; + case R.id.menu_invite_to_open_group: handleInviteToOpenGroup(); return true; case android.R.id.home: handleReturnToConversationList(); return true; } @@ -1036,6 +1047,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity startActivity(intent); } + private void handleInviteToOpenGroup() { + Intent intent = new Intent(this, SelectContactsActivity.class); + startActivityForResult(intent, INVITE_CONTACTS); + } + private void handleDistributionBroadcastEnabled(MenuItem item) { distributionType = DistributionTypes.BROADCAST; item.setChecked(true); @@ -1843,6 +1859,23 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity sendComplete(allocatedThreadId); } + private void sendOpenGroupInvitations(String[] contactIDs) { + final Context context = getApplicationContext(); + OpenGroupV2 openGroup = DatabaseFactory.getLokiThreadDatabase(context).getOpenGroupChat(threadId); + for (String contactID : contactIDs) { + Recipient recipient = Recipient.from(context, Address.fromSerialized(contactID), true); + VisibleMessage message = new VisibleMessage(); + message.setSentTimestamp(System.currentTimeMillis()); + OpenGroupInvitation openGroupInvitationMessage = new OpenGroupInvitation(); + openGroupInvitationMessage.setName(openGroup.getName()); + openGroupInvitationMessage.setUrl(openGroup.getJoinURL()); + message.setOpenGroupInvitation(openGroupInvitationMessage); + OutgoingTextMessage outgoingTextMessage = OutgoingTextMessage.fromOpenGroupInvitation(openGroupInvitationMessage, recipient, message.getSentTimestamp()); + DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(-1, outgoingTextMessage, message.getSentTimestamp()); + MessageSender.send(message, recipient.getAddress()); + } + } + private void updateToggleButtonState() { if (inputPanel.isRecordingInLockedMode()) { buttonToggle.display(sendButton); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java index ba7f4bcac3..f2b2d38b70 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationAdapter.java @@ -87,15 +87,17 @@ public class ConversationAdapter Collections.synchronizedMap(new LRUCache>(MAX_CACHE_SIZE)); private final SparseArray positionToCacheRef = new SparseArray<>(); - private static final int MESSAGE_TYPE_OUTGOING = 0; - private static final int MESSAGE_TYPE_INCOMING = 1; - private static final int MESSAGE_TYPE_UPDATE = 2; - private static final int MESSAGE_TYPE_AUDIO_OUTGOING = 3; - private static final int MESSAGE_TYPE_AUDIO_INCOMING = 4; - private static final int MESSAGE_TYPE_THUMBNAIL_OUTGOING = 5; - private static final int MESSAGE_TYPE_THUMBNAIL_INCOMING = 6; - private static final int MESSAGE_TYPE_DOCUMENT_OUTGOING = 7; - private static final int MESSAGE_TYPE_DOCUMENT_INCOMING = 8; + private static final int MESSAGE_TYPE_OUTGOING = 0; + private static final int MESSAGE_TYPE_INCOMING = 1; + private static final int MESSAGE_TYPE_UPDATE = 2; + private static final int MESSAGE_TYPE_AUDIO_OUTGOING = 3; + private static final int MESSAGE_TYPE_AUDIO_INCOMING = 4; + private static final int MESSAGE_TYPE_THUMBNAIL_OUTGOING = 5; + private static final int MESSAGE_TYPE_THUMBNAIL_INCOMING = 6; + private static final int MESSAGE_TYPE_DOCUMENT_OUTGOING = 7; + private static final int MESSAGE_TYPE_DOCUMENT_INCOMING = 8; + private static final int MESSAGE_TYPE_INVITATION_OUTGOING = 9; + private static final int MESSAGE_TYPE_INVITATION_INCOMING = 10; private final Set batchSelected = Collections.synchronizedSet(new HashSet()); @@ -281,10 +283,12 @@ public class ConversationAdapter case MESSAGE_TYPE_AUDIO_OUTGOING: case MESSAGE_TYPE_THUMBNAIL_OUTGOING: case MESSAGE_TYPE_DOCUMENT_OUTGOING: + case MESSAGE_TYPE_INVITATION_OUTGOING: case MESSAGE_TYPE_OUTGOING: return R.layout.conversation_item_sent; case MESSAGE_TYPE_AUDIO_INCOMING: case MESSAGE_TYPE_THUMBNAIL_INCOMING: case MESSAGE_TYPE_DOCUMENT_INCOMING: + case MESSAGE_TYPE_INVITATION_INCOMING: case MESSAGE_TYPE_INCOMING: return R.layout.conversation_item_received; case MESSAGE_TYPE_UPDATE: return R.layout.conversation_item_update; default: throw new IllegalArgumentException("unsupported item view type given to ConversationAdapter"); @@ -295,6 +299,9 @@ public class ConversationAdapter public int getItemViewType(@NonNull MessageRecord messageRecord) { if (messageRecord.isUpdate()) { return MESSAGE_TYPE_UPDATE; + } else if (messageRecord.isOpenGroupInvitation()) { + if (messageRecord.isOutgoing()) return MESSAGE_TYPE_INVITATION_OUTGOING; + else return MESSAGE_TYPE_INVITATION_INCOMING; } else if (hasAudio(messageRecord)) { if (messageRecord.isOutgoing()) return MESSAGE_TYPE_AUDIO_OUTGOING; else return MESSAGE_TYPE_AUDIO_INCOMING; diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java index b89a7b6962..1b7d11e743 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -63,6 +63,7 @@ import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAt import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview; import org.session.libsession.messaging.threads.recipients.Recipient; import org.session.libsession.messaging.threads.recipients.RecipientModifiedListener; +import org.session.libsession.messaging.utilities.UpdateMessageData; import org.session.libsession.utilities.GroupUtil; import org.session.libsession.utilities.TextSecurePreferences; import org.session.libsession.utilities.ThemeUtil; @@ -92,6 +93,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil; import org.thoughtcrime.securesms.loki.utilities.MentionUtilities; import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities; import org.thoughtcrime.securesms.loki.views.MessageAudioView; +import org.thoughtcrime.securesms.loki.views.OpenGroupInvitationView; import org.thoughtcrime.securesms.loki.views.ProfilePictureView; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.ImageSlide; @@ -156,6 +158,7 @@ public class ConversationItem extends LinearLayout private Stub documentViewStub; private Stub linkPreviewStub; private Stub stickerStub; + private Stub openGroupInvitationViewStub; private @Nullable EventListener eventListener; private int defaultBubbleColor; @@ -203,6 +206,7 @@ public class ConversationItem extends LinearLayout this.documentViewStub = new Stub<>(findViewById(R.id.document_view_stub)); this.linkPreviewStub = new Stub<>(findViewById(R.id.link_preview_stub)); this.stickerStub = new Stub<>(findViewById(R.id.sticker_view_stub)); + this.openGroupInvitationViewStub = new Stub<>(findViewById(R.id.open_group_invitation_stub)); this.groupSenderHolder = findViewById(R.id.group_sender_holder); this.quoteView = findViewById(R.id.quote_view); this.container = findViewById(R.id.container); @@ -467,7 +471,9 @@ public class ConversationItem extends LinearLayout bodyText.setOverflowText(null); } - bodyText.setText(text); + if (!messageRecord.isOpenGroupInvitation()) + bodyText.setText(text); + bodyText.setVisibility(View.VISIBLE); } } @@ -528,6 +534,7 @@ public class ConversationItem extends LinearLayout if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE); if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE); if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE); + if (openGroupInvitationViewStub.resolved()) openGroupInvitationViewStub.get().setVisibility(View.GONE); //noinspection ConstantConditions LinkPreview linkPreview = ((MmsMessageRecord) messageRecord).getLinkPreviews().get(0); @@ -564,6 +571,7 @@ public class ConversationItem extends LinearLayout if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE); if (linkPreviewStub.resolved()) linkPreviewStub.get().setVisibility(GONE); if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE); + if (openGroupInvitationViewStub.resolved()) openGroupInvitationViewStub.get().setVisibility(View.GONE); //noinspection ConstantConditions audioViewStub.get().setAudio(((MediaMmsMessageRecord) messageRecord).getSlideDeck().getAudioSlide(), showControls); @@ -580,6 +588,7 @@ public class ConversationItem extends LinearLayout if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE); if (linkPreviewStub.resolved()) linkPreviewStub.get().setVisibility(GONE); if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE); + if (openGroupInvitationViewStub.resolved()) openGroupInvitationViewStub.get().setVisibility(View.GONE); //noinspection ConstantConditions documentViewStub.get().setDocument(((MediaMmsMessageRecord) messageRecord).getSlideDeck().getDocumentSlide(), showControls); @@ -597,6 +606,7 @@ public class ConversationItem extends LinearLayout if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE); if (linkPreviewStub.resolved()) linkPreviewStub.get().setVisibility(GONE); if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE); + if (openGroupInvitationViewStub.resolved()) openGroupInvitationViewStub.get().setVisibility(View.GONE); //noinspection ConstantConditions List thumbnailSlides = ((MmsMessageRecord) messageRecord).getSlideDeck().getThumbnailSlides(); @@ -619,6 +629,29 @@ public class ConversationItem extends LinearLayout ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); footer.setVisibility(VISIBLE); + } else if (messageRecord.isOpenGroupInvitation()) { + openGroupInvitationViewStub.get().setVisibility(View.VISIBLE); + if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE); + if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE); + if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE); + if (linkPreviewStub.resolved()) linkPreviewStub.get().setVisibility(GONE); + if (stickerStub.resolved()) stickerStub.get().setVisibility(View.GONE); + + UpdateMessageData updateMessageData = UpdateMessageData.Companion.fromJSON(messageRecord.getBody()); + String name = null, url = null; + if (updateMessageData.getKind() instanceof UpdateMessageData.Kind.OpenGroupInvitation) { + UpdateMessageData.Kind.OpenGroupInvitation data = (UpdateMessageData.Kind.OpenGroupInvitation)updateMessageData.getKind(); + name = data.getGroupName(); + url = data.getGroupUrl(); + } + + openGroupInvitationViewStub.get().setOpenGroup(name, url, messageRecord.isOutgoing()); + openGroupInvitationViewStub.get().setOnLongClickListener(passthroughClickListener); + + bodyText.setVisibility(View.GONE); + + ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); } else { if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE); if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java index 024d1f51dd..81ec17bd0e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java @@ -47,13 +47,16 @@ public interface MmsSmsColumns { BASE_PENDING_INSECURE_SMS_FALLBACK, OUTGOING_CALL_TYPE}; + + // TODO: Clean unused keys + // Message attributes protected static final long MESSAGE_FORCE_SMS_BIT = 0x40; // Key Exchange Information protected static final long KEY_EXCHANGE_MASK = 0xFF00; protected static final long KEY_EXCHANGE_BIT = 0x8000; - protected static final long KEY_EXCHANGE_IDENTITY_VERIFIED_BIT = 0x4000; + protected static final long KEY_EXCHANGE_IDENTITY_VERIFIED_BIT = 0x40000; protected static final long KEY_EXCHANGE_IDENTITY_DEFAULT_BIT = 0x2000; protected static final long KEY_EXCHANGE_CORRUPTED_BIT = 0x1000; protected static final long KEY_EXCHANGE_INVALID_VERSION_BIT = 0x800; @@ -72,10 +75,13 @@ public interface MmsSmsColumns { protected static final long EXPIRATION_TIMER_UPDATE_BIT = 0x40000; protected static final long GROUP_UPDATE_MESSAGE_BIT = 0x80000; - // Data Extraction Information + // Data Extraction Notification protected static final long MEDIA_SAVED_EXTRACTION_BIT = 0x01000; protected static final long SCREENSHOT_EXTRACTION_BIT = 0x02000; + // Open Group Invitation + protected static final long OPEN_GROUP_INVITATION_BIT = 0x04000; + // Encrypted Storage Information XXX public static final long ENCRYPTION_MASK = 0xFF000000; // public static final long ENCRYPTION_SYMMETRIC_BIT = 0x80000000; Deprecated @@ -210,6 +216,10 @@ public interface MmsSmsColumns { return (type & SCREENSHOT_EXTRACTION_BIT) != 0; } + public static boolean isOpenGroupInvitation(long type) { + return (type & OPEN_GROUP_INVITATION_BIT) != 0; + } + public static boolean isIncomingCall(long type) { return type == INCOMING_CALL_TYPE; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index 226645b39c..1da23548da 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -350,7 +350,9 @@ public class SmsDatabase extends MessagingDatabase { if (((IncomingGroupMessage)message).isUpdateMessage()) type |= Types.GROUP_UPDATE_MESSAGE_BIT; } - if (message.isPush()) type |= Types.PUSH_MESSAGE_BIT; + if (message.isPush()) type |= Types.PUSH_MESSAGE_BIT; + + if (message.isOpenGroupInvitation()) type |= Types.OPEN_GROUP_INVITATION_BIT; Recipient recipient = Recipient.from(context, message.getSender(), true); @@ -443,8 +445,9 @@ public class SmsDatabase extends MessagingDatabase { { long type = Types.BASE_SENDING_TYPE; - if (message.isSecureMessage()) type |= (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT); - if (forceSms) type |= Types.MESSAGE_FORCE_SMS_BIT; + if (message.isSecureMessage()) type |= (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT); + if (forceSms) type |= Types.MESSAGE_FORCE_SMS_BIT; + if (message.isOpenGroupInvitation()) type |= Types.OPEN_GROUP_INVITATION_BIT; Address address = message.getRecipient().getAddress(); Map earlyDeliveryReceipts = earlyDeliveryReceiptCache.remove(date); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 42cb63eb1b..1651405d4c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -24,7 +24,7 @@ import org.session.libsession.messaging.threads.Address import org.session.libsession.messaging.threads.Address.Companion.fromSerialized import org.session.libsession.messaging.threads.GroupRecord import org.session.libsession.messaging.threads.recipients.Recipient -import org.session.libsession.messaging.utilities.ClosedGroupUpdateMessageData +import org.session.libsession.messaging.utilities.UpdateMessageData import org.session.libsession.utilities.GroupUtil import org.session.libsession.utilities.IdentityKeyUtil import org.session.libsession.utilities.TextSecurePreferences @@ -165,11 +165,15 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, mmsDatabase.endTransaction() } else { val smsDatabase = DatabaseFactory.getSmsDatabase(context) + val isOpenGroupInvitation = (message.openGroupInvitation != null) + val insertResult = if (message.sender == getUserPublicKey()) { - val textMessage = OutgoingTextMessage.from(message, targetRecipient) + val textMessage = if (isOpenGroupInvitation) OutgoingTextMessage.fromOpenGroupInvitation(message.openGroupInvitation, targetRecipient, message.sentTimestamp) + else OutgoingTextMessage.from(message, targetRecipient) smsDatabase.insertMessageOutbox(message.threadID ?: -1, textMessage, message.sentTimestamp!!) } else { - val textMessage = IncomingTextMessage.from(message, senderAddress, group, targetRecipient.expireMessages * 1000L) + val textMessage = if (isOpenGroupInvitation) IncomingTextMessage.fromOpenGroupInvitation(message.openGroupInvitation, senderAddress, message.sentTimestamp) + else IncomingTextMessage.from(message, senderAddress, group, targetRecipient.expireMessages * 1000L) val encrypted = IncomingEncryptedMessage(textMessage, textMessage.messageBody) smsDatabase.insertMessageInbox(encrypted, message.receivedTimestamp ?: 0) } @@ -475,7 +479,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, override fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection, admins: Collection, sentTimestamp: Long) { val group = SignalServiceGroup(type, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList()) val m = IncomingTextMessage(Address.fromSerialized(senderPublicKey), 1, sentTimestamp, "", Optional.of(group), 0, true) - val updateData = ClosedGroupUpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON() + val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON() val infoMessage = IncomingGroupMessage(m, groupID, updateData, true) val smsDB = DatabaseFactory.getSmsDatabase(context) smsDB.insertMessageInbox(infoMessage) @@ -485,7 +489,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, val userPublicKey = getUserPublicKey() val recipient = Recipient.from(context, Address.fromSerialized(groupID), false) - val updateData = ClosedGroupUpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON() ?: "" + val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON() ?: "" val infoMessage = OutgoingGroupMediaMessage(recipient, updateData, groupID, null, sentTimestamp, 0, true, null, listOf(), listOf()) val mmsDB = DatabaseFactory.getMmsDatabase(context) val mmsSmsDB = DatabaseFactory.getMmsSmsDatabase(context) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java index f98dcda5d9..35a10fce3c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java @@ -145,6 +145,10 @@ public abstract class DisplayRecord { return isMediaSavedExtraction() || isScreenshotExtraction(); } + public boolean isOpenGroupInvitation() { + return MmsSmsColumns.Types.isOpenGroupInvitation(type); + } + public boolean isCallLog() { return SmsDatabase.Types.isCallLog(type); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java index 8380c41633..441b6cb988 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -26,8 +26,8 @@ import android.text.style.StyleSpan; import network.loki.messenger.R; import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage; -import org.session.libsession.messaging.utilities.ClosedGroupUpdateMessageBuilder; -import org.session.libsession.messaging.utilities.ClosedGroupUpdateMessageData; +import org.session.libsession.messaging.utilities.UpdateMessageBuilder; +import org.session.libsession.messaging.utilities.UpdateMessageData; import org.thoughtcrime.securesms.database.MmsSmsColumns; import org.thoughtcrime.securesms.database.SmsDatabase; import org.session.libsession.database.documents.IdentityKeyMismatch; @@ -93,14 +93,14 @@ public abstract class MessageRecord extends DisplayRecord { @Override public SpannableString getDisplayBody(@NonNull Context context) { if(isGroupUpdateMessage()) { - ClosedGroupUpdateMessageData updateMessageData = ClosedGroupUpdateMessageData.Companion.fromJSON(getBody()); - return new SpannableString(ClosedGroupUpdateMessageBuilder.INSTANCE.buildGroupUpdateMessage(context, updateMessageData, getIndividualRecipient().getAddress().serialize(), isOutgoing())); + UpdateMessageData updateMessageData = UpdateMessageData.Companion.fromJSON(getBody()); + return new SpannableString(UpdateMessageBuilder.INSTANCE.buildGroupUpdateMessage(context, updateMessageData, getIndividualRecipient().getAddress().serialize(), isOutgoing())); } else if (isExpirationTimerUpdate()) { int seconds = (int) (getExpiresIn() / 1000); - return new SpannableString(ClosedGroupUpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(context, seconds, getIndividualRecipient().getAddress().serialize(), isOutgoing())); + return new SpannableString(UpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(context, seconds, getIndividualRecipient().getAddress().serialize(), isOutgoing())); } else if (isDataExtraction()) { - if (isScreenshotExtraction()) return new SpannableString((ClosedGroupUpdateMessageBuilder.INSTANCE.buildDataExtractionMessage(context, DataExtractionNotificationInfoMessage.Kind.SCREENSHOT, getIndividualRecipient().getAddress().serialize()))); - else if (isMediaSavedExtraction()) return new SpannableString((ClosedGroupUpdateMessageBuilder.INSTANCE.buildDataExtractionMessage(context, DataExtractionNotificationInfoMessage.Kind.MEDIA_SAVED, getIndividualRecipient().getAddress().serialize()))); + if (isScreenshotExtraction()) return new SpannableString((UpdateMessageBuilder.INSTANCE.buildDataExtractionMessage(context, DataExtractionNotificationInfoMessage.Kind.SCREENSHOT, getIndividualRecipient().getAddress().serialize()))); + else if (isMediaSavedExtraction()) return new SpannableString((UpdateMessageBuilder.INSTANCE.buildDataExtractionMessage(context, DataExtractionNotificationInfoMessage.Kind.MEDIA_SAVED, getIndividualRecipient().getAddress().serialize()))); } // TODO below lines are left here for compatibility with older group update messages, it can be deleted later on else if (isGroupUpdate() && isOutgoing()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java index b0183cff63..1833ac4270 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java @@ -77,6 +77,8 @@ public class ThreadRecord extends DisplayRecord { return emphasisAdded(context.getString(R.string.ThreadRecord_group_updated)); } else if (isGroupQuit()) { return emphasisAdded(context.getString(R.string.ThreadRecord_left_the_group)); + } else if (isOpenGroupInvitation()) { + return emphasisAdded(context.getString(R.string.ThreadRecord_open_group_invitation)); } else if (isKeyExchange()) { return emphasisAdded(context.getString(R.string.ConversationListItem_key_exchange_message)); } else if (SmsDatabase.Types.isFailedDecryptType(type)) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt index c270797c6c..70bb78d8b6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt @@ -150,9 +150,10 @@ class PublicChatManager(private val context: Context) { val groupId = "$server.$room" val threadId = GroupManager.getOpenGroupThreadID(groupId, context) val groupAddress = threadDB.getRecipientForThreadId(threadId)!!.address.serialize() - GroupManager.deleteGroup(groupAddress, context) - - Util.runOnMain { startPollersIfNeeded() } + ThreadUtils.queue { + GroupManager.deleteGroup(groupAddress, context) // Must be invoked on a background thread + Util.runOnMain { startPollersIfNeeded() } + } } private fun refreshChatsAndPollers() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/views/OpenGroupInvitationView.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/views/OpenGroupInvitationView.kt new file mode 100644 index 0000000000..e1a26f1669 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/views/OpenGroupInvitationView.kt @@ -0,0 +1,79 @@ +package org.thoughtcrime.securesms.loki.views + +import android.content.Context +import android.content.res.ColorStateList +import android.graphics.Color +import android.util.AttributeSet +import android.view.View +import android.widget.* +import androidx.appcompat.app.AlertDialog +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import network.loki.messenger.R +import org.session.libsession.utilities.GroupUtil +import org.session.libsession.utilities.OpenGroupUrlParser +import org.session.libsignal.utilities.logging.Log +import org.thoughtcrime.securesms.groups.GroupManager +import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol +import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities + +class OpenGroupInvitationView : FrameLayout { + private val joinButton: ImageView + private val openGroupIconContainer: RelativeLayout + private val openGroupIconImageView: ImageView + private val nameTextView: TextView + private val urlTextView: TextView + private var url: String = "" + + constructor(context: Context): this(context, null) + + constructor(context: Context, attrs: AttributeSet?): this(context, attrs, 0) + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int): super(context, attrs, defStyleAttr) { + View.inflate(context, R.layout.open_group_invitation_view, this) + joinButton = findViewById(R.id.join_open_group_button) + openGroupIconContainer = findViewById(R.id.open_group_icon_image_view_container) + openGroupIconImageView = findViewById(R.id.open_group_icon_image_view) + nameTextView = findViewById(R.id.name_text_view) + urlTextView = findViewById(R.id.url_text_view) + joinButton.setOnClickListener { joinOpenGroup(url) } + } + + fun setOpenGroup(name: String, url: String, isOutgoing: Boolean = false) { + nameTextView.text = name + urlTextView.text = OpenGroupUrlParser.trimQueryParameter(url) + this.url = url + joinButton.visibility = if (isOutgoing) View.GONE else View.VISIBLE + openGroupIconContainer.visibility = if (isOutgoing) View.VISIBLE else View.GONE + } + + private fun joinOpenGroup(url: String) { + val openGroup = OpenGroupUrlParser.parseUrl(url) + val builder = AlertDialog.Builder(context) + builder.setTitle(context.getString(R.string.ConversationActivity_join_open_group, nameTextView.text.toString())) + builder.setCancelable(true) + val message: String = + context.getString(R.string.ConversationActivity_join_open_group_confirmation_message, nameTextView.text.toString()) + builder.setMessage(message) + builder.setPositiveButton(R.string.yes) { dialog, _ -> + GlobalScope.launch(Dispatchers.IO) { + try { + dialog.dismiss() + val group = OpenGroupUtilities.addGroup( + context, + openGroup.server, + openGroup.room, + openGroup.serverPublicKey + ) + MultiDeviceProtocol.forceSyncConfigurationNowIfNeeded(context) + } catch (e: Exception) { + Log.e("Loki", "Failed to join open group.", e) + Toast.makeText(context, R.string.activity_join_public_chat_error, Toast.LENGTH_SHORT).show() + } + } + } + builder.setNegativeButton(R.string.no, null) + builder.show() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java index 376262cf7c..cf96ace8ce 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java @@ -481,6 +481,8 @@ public class DefaultMessageNotifier implements MessageNotifier { String message = slideDeck.getBody() + ": " + record.getBody(); int italicLength = message.length() - body.length(); body = SpanUtil.italic(message, italicLength); + } else if (record.isOpenGroupInvitation()) { + body = SpanUtil.italic(context.getString(R.string.ThreadRecord_open_group_invitation)); } if (threadRecipients == null || !threadRecipients.isMuted()) { diff --git a/app/src/main/res/layout/conversation_item_received.xml b/app/src/main/res/layout/conversation_item_received.xml index f0c853828c..ade3ea2c78 100644 --- a/app/src/main/res/layout/conversation_item_received.xml +++ b/app/src/main/res/layout/conversation_item_received.xml @@ -140,6 +140,12 @@ android:layout_height="wrap_content" android:layout="@layout/conversation_item_received_link_preview" /> + + + \ No newline at end of file diff --git a/app/src/main/res/layout/conversation_item_sent.xml b/app/src/main/res/layout/conversation_item_sent.xml index 9dc10706b1..b6a7ff291a 100644 --- a/app/src/main/res/layout/conversation_item_sent.xml +++ b/app/src/main/res/layout/conversation_item_sent.xml @@ -50,13 +50,13 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/large_spacing" - android:layout_marginBottom="@dimen/medium_spacing" android:layout_marginEnd="@dimen/large_spacing" + android:layout_marginBottom="@dimen/medium_spacing" android:visibility="gone" app:message_type="outgoing" app:quote_colorPrimary="@color/text" app:quote_colorSecondary="@color/text" - tools:visibility="visible"/> + tools:visibility="visible" /> + + + \ No newline at end of file diff --git a/app/src/main/res/layout/open_group_invitation_view.xml b/app/src/main/res/layout/open_group_invitation_view.xml new file mode 100644 index 0000000000..2a360a4a62 --- /dev/null +++ b/app/src/main/res/layout/open_group_invitation_view.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/conversation_invite_open_group.xml b/app/src/main/res/menu/conversation_invite_open_group.xml new file mode 100644 index 0000000000..0cef563b7c --- /dev/null +++ b/app/src/main/res/menu/conversation_invite_open_group.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 5fbc37a757..f57faa12c5 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -151,6 +151,10 @@ La pièce jointe dépasse la limite de taille autorisée. L’appareil photo n’est pas disponible Impossible d’enregistrer l’audio ! + Ajouter des membres + Rejoindre %s + Êtes-vous sûr de vouloir rejoindre le group public %s? + Il n’y a aucune appli pour gérer ce lien sur votre appareil. Pour envoyer des messages audio, autorisez Session à accéder à votre microphone. Session exige l’autorisation Microphone afin d’envoyer des messages audio, mais elle a été refusée définitivement. Veuillez accéder au menu des paramètres des applis, sélectionner « Autorisations » et activer « Microphone ». @@ -599,6 +603,8 @@ Vous avez reçu un message d’échange de clés pour une version de protocole i Votre numéro de sécurité avec %s a changé Vous avez marqué comme vérifié Vous avez marqué comme non vérifié + Cette conversation est vide + Invitation à un groupe public Mise à jour de Session Une nouvelle version de Session est proposée. Touchez pour lancer la mise à jour @@ -782,6 +788,9 @@ Vous avez reçu un message d’échange de clés pour une version de protocole i Lire Mettre en pause Télécharger + + Rejoindre + Invitation à un groupe public Contenu audio Vidéo diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 83997f2bdf..383867b4ae 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -175,6 +175,9 @@ Camera unavailable Unable to record audio! There is no app available to handle this link on your device. + Add members + Join %s + Are you sure you want to join the %s open group? Session needs microphone access to send audio messages. Session needs microphone access to send audio messages, but it has been permanently denied. Please continue to app settings, select \"Permissions\", and enable \"Microphone\". @@ -722,6 +725,7 @@ You marked verified You marked unverified This conversation is empty + Open group invitation Session update @@ -948,6 +952,10 @@ Pause Download + + Join + Open group invitation + Audio Video diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/IncomingTextMessage.java b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/IncomingTextMessage.java index 35b9d40a2c..690143a188 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/IncomingTextMessage.java +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/IncomingTextMessage.java @@ -5,8 +5,10 @@ import android.os.Parcelable; import androidx.annotation.Nullable; +import org.session.libsession.messaging.messages.visible.OpenGroupInvitation; import org.session.libsession.messaging.messages.visible.VisibleMessage; import org.session.libsession.messaging.threads.Address; +import org.session.libsession.messaging.utilities.UpdateMessageData; import org.session.libsession.utilities.GroupUtil; import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.service.api.messages.SignalServiceGroup; @@ -40,6 +42,8 @@ public class IncomingTextMessage implements Parcelable { private final long expiresInMillis; private final boolean unidentified; + private boolean isOpenGroupInvitation = false; + public IncomingTextMessage(Address sender, int senderDeviceId, long sentTimestampMillis, String encodedBody, Optional group, long expiresInMillis, boolean unidentified) @@ -94,6 +98,7 @@ public class IncomingTextMessage implements Parcelable { this.subscriptionId = base.getSubscriptionId(); this.expiresInMillis = base.getExpiresIn(); this.unidentified = base.isUnidentified(); + this.isOpenGroupInvitation= base.isOpenGroupInvitation(); } public static IncomingTextMessage from(VisibleMessage message, @@ -104,6 +109,18 @@ public class IncomingTextMessage implements Parcelable { return new IncomingTextMessage(sender, 1, message.getSentTimestamp(), message.getText(), group, expiresInMillis, false); } + public static IncomingTextMessage fromOpenGroupInvitation(OpenGroupInvitation openGroupInvitation, Address sender, Long sentTimestamp) + { + String url = openGroupInvitation.getUrl(); + String name = openGroupInvitation.getName(); + if (url == null || name == null) { return null; } + // FIXME: Doing toJSON() to get the body here is weird + String body = UpdateMessageData.Companion.buildOpenGroupInvitation(url, name).toJSON(); + IncomingTextMessage incomingTextMessage = new IncomingTextMessage(sender, 1, sentTimestamp, body, Optional.absent(), 0, false); + incomingTextMessage.isOpenGroupInvitation = true; + return incomingTextMessage; + } + public int getSubscriptionId() { return subscriptionId; } @@ -163,6 +180,9 @@ public class IncomingTextMessage implements Parcelable { public boolean isUnidentified() { return unidentified; } + + public boolean isOpenGroupInvitation() { return isOpenGroupInvitation; } + @Override public int describeContents() { return 0; diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingTextMessage.java b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingTextMessage.java index 9ebd44891e..ac5b240404 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingTextMessage.java +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingTextMessage.java @@ -1,15 +1,17 @@ package org.session.libsession.messaging.messages.signal; +import org.session.libsession.messaging.messages.visible.OpenGroupInvitation; import org.session.libsession.messaging.messages.visible.VisibleMessage; import org.session.libsession.messaging.threads.recipients.Recipient; +import org.session.libsession.messaging.utilities.UpdateMessageData; public class OutgoingTextMessage { - private final Recipient recipient; private final String message; private final int subscriptionId; private final long expiresIn; private final long sentTimestampMillis; + private boolean isOpenGroupInvitation = false; public OutgoingTextMessage(Recipient recipient, String message, long expiresIn, int subscriptionId, long sentTimestampMillis) { this.recipient = recipient; @@ -23,6 +25,17 @@ public class OutgoingTextMessage { return new OutgoingTextMessage(recipient, message.getText(), recipient.getExpireMessages() * 1000, -1, message.getSentTimestamp()); } + public static OutgoingTextMessage fromOpenGroupInvitation(OpenGroupInvitation openGroupInvitation, Recipient recipient, Long sentTimestamp) { + String url = openGroupInvitation.getUrl(); + String name = openGroupInvitation.getName(); + if (url == null || name == null) { return null; } + // FIXME: Doing toJSON() to get the body here is weird + String body = UpdateMessageData.Companion.buildOpenGroupInvitation(url, name).toJSON(); + OutgoingTextMessage outgoingTextMessage = new OutgoingTextMessage(recipient, body, 0, -1, sentTimestamp); + outgoingTextMessage.isOpenGroupInvitation = true; + return outgoingTextMessage; + } + public long getExpiresIn() { return expiresIn; } @@ -46,4 +59,6 @@ public class OutgoingTextMessage { public boolean isSecureMessage() { return true; } + + public boolean isOpenGroupInvitation() { return isOpenGroupInvitation; } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/OpenGroupInvitation.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/OpenGroupInvitation.kt new file mode 100644 index 0000000000..8c521df067 --- /dev/null +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/OpenGroupInvitation.kt @@ -0,0 +1,38 @@ +package org.session.libsession.messaging.messages.visible + +import org.session.libsignal.service.internal.push.SignalServiceProtos +import org.session.libsignal.utilities.logging.Log + +class OpenGroupInvitation() { + var url: String? = null + var name: String? = null + + fun isValid(): Boolean { + return (url != null && name != null) + } + + companion object { + const val TAG = "OpenGroupInvitation" + + fun fromProto(proto: SignalServiceProtos.DataMessage.OpenGroupInvitation): OpenGroupInvitation { + return OpenGroupInvitation(proto.url, proto.name) + } + } + + constructor(url: String?, serverName: String?): this() { + this.url = url + this.name = serverName + } + + fun toProto(): SignalServiceProtos.DataMessage.OpenGroupInvitation? { + val openGroupInvitationProto = SignalServiceProtos.DataMessage.OpenGroupInvitation.newBuilder() + openGroupInvitationProto.url = url + openGroupInvitationProto.name = name + return try { + openGroupInvitationProto.build() + } catch (e: Exception) { + Log.w(TAG, "Couldn't construct open group invitation proto from: $this.") + null + } + } +} \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt index 8c795d22e8..864a919bd1 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt @@ -22,6 +22,7 @@ class VisibleMessage : Message() { var quote: Quote? = null var linkPreview: LinkPreview? = null var profile: Profile? = null + var openGroupInvitation: OpenGroupInvitation? = null override val isSelfSendValid: Boolean = true @@ -29,6 +30,7 @@ class VisibleMessage : Message() { override fun isValid(): Boolean { if (!super.isValid()) return false if (attachmentIDs.isNotEmpty()) return true + if (openGroupInvitation != null) return true val text = text?.trim() ?: return false if (text.isNotEmpty()) return true return false @@ -55,7 +57,12 @@ class VisibleMessage : Message() { val linkPreview = LinkPreview.fromProto(linkPreviewProto) result.linkPreview = linkPreview } - // TODO: Contact + val openGroupInvitationProto = if (dataMessage.hasOpenGroupInvitation()) dataMessage.openGroupInvitation else null + if (openGroupInvitationProto != null) { + val openGroupInvitation = OpenGroupInvitation.fromProto(openGroupInvitationProto) + result.openGroupInvitation = openGroupInvitation + } + // TODO Contact val profile = Profile.fromProto(dataMessage) if (profile != null) { result.profile = profile } return result @@ -66,7 +73,7 @@ class VisibleMessage : Message() { val proto = SignalServiceProtos.Content.newBuilder() val dataMessage: SignalServiceProtos.DataMessage.Builder // Profile - val profileProto = profile?.let { it.toProto() } + val profileProto = profile?.toProto() if (profileProto != null) { dataMessage = profileProto.toBuilder() } else { @@ -75,15 +82,20 @@ class VisibleMessage : Message() { // Text if (text != null) { dataMessage.body = text } // Quote - val quoteProto = quote?.let { it.toProto() } + val quoteProto = quote?.toProto() if (quoteProto != null) { dataMessage.quote = quoteProto } // Link preview - val linkPreviewProto = linkPreview?.let { it.toProto() } + val linkPreviewProto = linkPreview?.toProto() if (linkPreviewProto != null) { dataMessage.addAllPreview(listOf(linkPreviewProto)) } + // Open group invitation + val openGroupInvitationProto = openGroupInvitation?.toProto() + if (openGroupInvitationProto != null) { + dataMessage.openGroupInvitation = openGroupInvitationProto + } // Attachments val database = MessagingModuleConfiguration.shared.messageDataProvider val attachments = attachmentIDs.mapNotNull { database.getSignalAttachmentPointer(it) } diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt index 6a4b986744..57c06af221 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt @@ -7,6 +7,7 @@ import org.session.libsession.messaging.jobs.JobQueue import org.session.libsession.messaging.messages.Message import org.session.libsession.messaging.messages.control.* import org.session.libsession.messaging.messages.visible.Attachment +import org.session.libsession.messaging.messages.visible.OpenGroupInvitation import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.sending_receiving.attachments.PointerAttachment import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage @@ -52,6 +53,7 @@ fun MessageReceiver.handle(message: Message, proto: SignalServiceProtos.Content, } } +// region Control Messages private fun MessageReceiver.handleReadReceipt(message: ReadReceipt) { val context = MessagingModuleConfiguration.shared.context SSKEnvironment.shared.readReceiptManager.processReadReceipts(context, message.sender!!, message.timestamps!!, message.receivedTimestamp!!) @@ -140,7 +142,9 @@ private fun handleConfigurationMessage(message: ConfigurationMessage) { } storage.addContacts(message.contacts) } +//endregion +// region Visible Messages fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalServiceProtos.Content, openGroupID: String?) { val storage = MessagingModuleConfiguration.shared.storage val context = MessagingModuleConfiguration.shared.context @@ -233,7 +237,9 @@ fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalS //Notify the user if needed SSKEnvironment.shared.notificationManager.updateNotification(context, threadID) } +//endregion +// region Closed Groups private fun MessageReceiver.handleClosedGroupControlMessage(message: ClosedGroupControlMessage) { when (message.kind!!) { is ClosedGroupControlMessage.Kind.New -> handleNewClosedGroup(message) @@ -557,4 +563,5 @@ fun MessageReceiver.disableLocalGroupAndUnsubscribe(groupPublicKey: String, grou storage.removeMember(groupID, Address.fromSerialized(userPublicKey)) // Notify the PN server PushNotificationAPI.performOperation(PushNotificationAPI.ClosedGroupOperation.Unsubscribe, groupPublicKey, userPublicKey) -} \ No newline at end of file +} +// endregion diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/ClosedGroupUpdateMessageBuilder.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt similarity index 91% rename from libsession/src/main/java/org/session/libsession/messaging/utilities/ClosedGroupUpdateMessageBuilder.kt rename to libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt index 33a6385692..04484f9cc8 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/ClosedGroupUpdateMessageBuilder.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt @@ -6,9 +6,9 @@ import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage import org.session.libsession.utilities.ExpirationUtil -object ClosedGroupUpdateMessageBuilder { +object UpdateMessageBuilder { - fun buildGroupUpdateMessage(context: Context, updateMessageData: ClosedGroupUpdateMessageData, sender: String? = null, isOutgoing: Boolean = false): String { + fun buildGroupUpdateMessage(context: Context, updateMessageData: UpdateMessageData, sender: String? = null, isOutgoing: Boolean = false): String { var message = "" val updateData = updateMessageData.kind ?: return message if (!isOutgoing && sender == null) return message @@ -17,21 +17,21 @@ object ClosedGroupUpdateMessageBuilder { } else { context.getString(R.string.MessageRecord_you) } when (updateData) { - is ClosedGroupUpdateMessageData.Kind.GroupCreation -> { + is UpdateMessageData.Kind.GroupCreation -> { message = if (isOutgoing) { context.getString(R.string.MessageRecord_you_created_a_new_group) } else { context.getString(R.string.MessageRecord_s_added_you_to_the_group, senderName) } } - is ClosedGroupUpdateMessageData.Kind.GroupNameChange -> { + is UpdateMessageData.Kind.GroupNameChange -> { message = if (isOutgoing) { context.getString(R.string.MessageRecord_you_renamed_the_group_to_s, updateData.name) } else { context.getString(R.string.MessageRecord_s_renamed_the_group_to_s, senderName, updateData.name) } } - is ClosedGroupUpdateMessageData.Kind.GroupMemberAdded -> { + is UpdateMessageData.Kind.GroupMemberAdded -> { val members = updateData.updatedMembers.joinToString(", ") { MessagingModuleConfiguration.shared.storage.getDisplayNameForRecipient(it) ?: it } @@ -41,7 +41,7 @@ object ClosedGroupUpdateMessageBuilder { context.getString(R.string.MessageRecord_s_added_s_to_the_group, senderName, members) } } - is ClosedGroupUpdateMessageData.Kind.GroupMemberRemoved -> { + is UpdateMessageData.Kind.GroupMemberRemoved -> { val storage = MessagingModuleConfiguration.shared.storage val userPublicKey = storage.getUserPublicKey()!! // 1st case: you are part of the removed members @@ -63,7 +63,7 @@ object ClosedGroupUpdateMessageBuilder { } } } - is ClosedGroupUpdateMessageData.Kind.GroupMemberLeft -> { + is UpdateMessageData.Kind.GroupMemberLeft -> { message = if (isOutgoing) { context.getString(R.string.MessageRecord_left_group) } else { diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/ClosedGroupUpdateMessageData.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt similarity index 64% rename from libsession/src/main/java/org/session/libsession/messaging/utilities/ClosedGroupUpdateMessageData.kt rename to libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt index 47efd03a4c..062576ea6c 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/ClosedGroupUpdateMessageData.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt @@ -9,7 +9,7 @@ import org.session.libsignal.utilities.logging.Log import java.util.* // class used to save update messages details -class ClosedGroupUpdateMessageData () { +class UpdateMessageData () { var kind: Kind? = null @@ -20,7 +20,8 @@ class ClosedGroupUpdateMessageData () { JsonSubTypes.Type(Kind.GroupNameChange::class, name = "GroupNameChange"), JsonSubTypes.Type(Kind.GroupMemberAdded::class, name = "GroupMemberAdded"), JsonSubTypes.Type(Kind.GroupMemberRemoved::class, name = "GroupMemberRemoved"), - JsonSubTypes.Type(Kind.GroupMemberLeft::class, name = "GroupMemberLeft") + JsonSubTypes.Type(Kind.GroupMemberLeft::class, name = "GroupMemberLeft"), + JsonSubTypes.Type(Kind.OpenGroupInvitation::class, name = "OpenGroupInvitation") ) sealed class Kind() { class GroupCreation(): Kind() @@ -34,6 +35,9 @@ class ClosedGroupUpdateMessageData () { constructor(): this(Collections.emptyList()) } class GroupMemberLeft(): Kind() + class OpenGroupInvitation(val groupUrl: String, val groupName: String): Kind() { + constructor(): this("", "") + } } constructor(kind: Kind): this() { @@ -41,22 +45,26 @@ class ClosedGroupUpdateMessageData () { } companion object { - val TAG = ClosedGroupUpdateMessageData::class.simpleName + val TAG = UpdateMessageData::class.simpleName - fun buildGroupUpdate(type: SignalServiceGroup.Type, name: String, members: Collection): ClosedGroupUpdateMessageData? { + fun buildGroupUpdate(type: SignalServiceGroup.Type, name: String, members: Collection): UpdateMessageData? { return when(type) { - SignalServiceGroup.Type.CREATION -> ClosedGroupUpdateMessageData(Kind.GroupCreation()) - SignalServiceGroup.Type.NAME_CHANGE -> ClosedGroupUpdateMessageData(Kind.GroupNameChange(name)) - SignalServiceGroup.Type.MEMBER_ADDED -> ClosedGroupUpdateMessageData(Kind.GroupMemberAdded(members)) - SignalServiceGroup.Type.MEMBER_REMOVED -> ClosedGroupUpdateMessageData(Kind.GroupMemberRemoved(members)) - SignalServiceGroup.Type.QUIT -> ClosedGroupUpdateMessageData(Kind.GroupMemberLeft()) + SignalServiceGroup.Type.CREATION -> UpdateMessageData(Kind.GroupCreation()) + SignalServiceGroup.Type.NAME_CHANGE -> UpdateMessageData(Kind.GroupNameChange(name)) + SignalServiceGroup.Type.MEMBER_ADDED -> UpdateMessageData(Kind.GroupMemberAdded(members)) + SignalServiceGroup.Type.MEMBER_REMOVED -> UpdateMessageData(Kind.GroupMemberRemoved(members)) + SignalServiceGroup.Type.QUIT -> UpdateMessageData(Kind.GroupMemberLeft()) else -> null } } - fun fromJSON(json: String): ClosedGroupUpdateMessageData? { + fun buildOpenGroupInvitation(url: String, name: String): UpdateMessageData { + return UpdateMessageData(Kind.OpenGroupInvitation(url, name)) + } + + fun fromJSON(json: String): UpdateMessageData? { return try { - JsonUtil.fromJson(json, ClosedGroupUpdateMessageData::class.java) + JsonUtil.fromJson(json, UpdateMessageData::class.java) } catch (e: JsonParseException) { Log.e(TAG, "${e.message}") null diff --git a/libsession/src/main/java/org/session/libsession/utilities/OpenGroupUrlParser.kt b/libsession/src/main/java/org/session/libsession/utilities/OpenGroupUrlParser.kt new file mode 100644 index 0000000000..ac7f9ad64f --- /dev/null +++ b/libsession/src/main/java/org/session/libsession/utilities/OpenGroupUrlParser.kt @@ -0,0 +1,36 @@ +package org.session.libsession.utilities + +import okhttp3.HttpUrl + +object OpenGroupUrlParser { + + sealed class Error(val description: String) : Exception(description) { + object MalformedURL : Error("Malformed URL.") + object NoRoom : Error("No room specified in the URL.") + object NoPublicKey : Error("No public key specified in the URL.") + object InvalidPublicKey : Error("Invalid public key provided.") + } + + private const val suffix = "/" + private const val queryPrefix = "public_key" + + fun parseUrl(string: String): V2OpenGroupInfo { + // URL has to start with 'http://' + val urlWithPrefix = if (!string.startsWith("http")) "http://$string" else string + // If the URL is malformed, throw an exception + val url = HttpUrl.parse(urlWithPrefix) ?: throw Error.MalformedURL + // Parse components + val server = HttpUrl.Builder().scheme(url.scheme()).host(url.host()).port(url.port()).build().toString().removeSuffix(suffix) + val room = url.pathSegments().firstOrNull { !it.isNullOrEmpty() } ?: throw Error.NoRoom + val publicKey = url.queryParameter(queryPrefix) ?: throw Error.NoPublicKey + if (publicKey.length != 64) throw Error.InvalidPublicKey + // Return + return V2OpenGroupInfo(server,room,publicKey) + } + + fun trimQueryParameter(string: String): String { + return string.substringBefore("?$queryPrefix") + } +} + +class V2OpenGroupInfo(val server: String, val room: String, val serverPublicKey: String) diff --git a/libsession/src/test/java/org/session/libsession/utilities/OpenGroupUrlParserTest.kt b/libsession/src/test/java/org/session/libsession/utilities/OpenGroupUrlParserTest.kt new file mode 100644 index 0000000000..38a244699d --- /dev/null +++ b/libsession/src/test/java/org/session/libsession/utilities/OpenGroupUrlParserTest.kt @@ -0,0 +1,87 @@ +package org.session.libsession.utilities + +import org.junit.Test +import org.junit.Assert.* + +class OpenGroupUrlParserTest { + + @Test + fun parseUrlTest() { + val inputUrl = "https://sessionopengroup.co/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c" + + val expectedHost = "https://sessionopengroup.co" + val expectedRoom = "main" + val expectedPublicKey = "658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c" + + val result = OpenGroupUrlParser.parseUrl(inputUrl) + assertEquals(expectedHost, result.server) + assertEquals(expectedRoom, result.room) + assertEquals(expectedPublicKey, result.serverPublicKey) + } + + @Test + fun parseUrlNoHttpTest() { + val inputUrl = "sessionopengroup.co/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c" + + val expectedHost = "http://sessionopengroup.co" + val expectedRoom = "main" + val expectedPublicKey = "658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c" + + val result = OpenGroupUrlParser.parseUrl(inputUrl) + assertEquals(expectedHost, result.server) + assertEquals(expectedRoom, result.room) + assertEquals(expectedPublicKey, result.serverPublicKey) + } + + @Test + fun parseUrlWithIpTest() { + val inputUrl = "https://143.198.213.255:80/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c" + + val expectedHost = "https://143.198.213.255:80" + val expectedRoom = "main" + val expectedPublicKey = "658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c" + + val result = OpenGroupUrlParser.parseUrl(inputUrl) + assertEquals(expectedHost, result.server) + assertEquals(expectedRoom, result.room) + assertEquals(expectedPublicKey, result.serverPublicKey) + } + + @Test + fun parseUrlWithIpAndNoHttpTest() { + val inputUrl = "143.198.213.255/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c" + + val expectedHost = "http://143.198.213.255" + val expectedRoom = "main" + val expectedPublicKey = "658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c" + + val result = OpenGroupUrlParser.parseUrl(inputUrl) + assertEquals(expectedHost, result.server) + assertEquals(expectedRoom, result.room) + assertEquals(expectedPublicKey, result.serverPublicKey) + } + + @Test(expected = OpenGroupUrlParser.Error.MalformedURL::class) + fun parseUrlMalformedUrlTest() { + val inputUrl = "file:sessionopengroup.co/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c" + OpenGroupUrlParser.parseUrl(inputUrl) + } + + @Test(expected = OpenGroupUrlParser.Error.NoRoom::class) + fun parseUrlNoRoomSpecifiedTest() { + val inputUrl = "https://sessionopengroup.comain?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231c" + OpenGroupUrlParser.parseUrl(inputUrl) + } + + @Test(expected = OpenGroupUrlParser.Error.NoPublicKey::class) + fun parseUrlNoPublicKeySpecifiedTest() { + val inputUrl = "https://sessionopengroup.co/main" + OpenGroupUrlParser.parseUrl(inputUrl) + } + + @Test(expected = OpenGroupUrlParser.Error.InvalidPublicKey::class) + fun parseUrlInvalidPublicKeyProviedTest() { + val inputUrl = "https://sessionopengroup.co/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adff" + OpenGroupUrlParser.parseUrl(inputUrl) + } +} diff --git a/libsignal/protobuf/SignalService.proto b/libsignal/protobuf/SignalService.proto index c748919c4a..624446adcd 100644 --- a/libsignal/protobuf/SignalService.proto +++ b/libsignal/protobuf/SignalService.proto @@ -40,7 +40,7 @@ message Content { optional ReceiptMessage receiptMessage = 5; optional TypingMessage typingMessage = 6; optional ConfigurationMessage configurationMessage = 7; - optional DataExtractionNotification dataExtractionNotification = 82; + optional DataExtractionNotification dataExtractionNotification = 8; } message KeyPair { @@ -102,6 +102,13 @@ message DataMessage { optional string profilePicture = 2; } + message OpenGroupInvitation { + // @required + required string url = 1; + // @required + required string name = 3; + } + message ClosedGroupControlMessage { enum Type { @@ -140,6 +147,7 @@ message DataMessage { optional Quote quote = 8; repeated Preview preview = 10; optional LokiProfile profile = 101; + optional OpenGroupInvitation openGroupInvitation = 102; optional ClosedGroupControlMessage closedGroupControlMessage = 104; optional string syncTarget = 105; } diff --git a/libsignal/src/main/java/org/session/libsignal/service/internal/push/SignalServiceProtos.java b/libsignal/src/main/java/org/session/libsignal/service/internal/push/SignalServiceProtos.java index 50aa3e4792..773b46f092 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/internal/push/SignalServiceProtos.java +++ b/libsignal/src/main/java/org/session/libsignal/service/internal/push/SignalServiceProtos.java @@ -1765,17 +1765,17 @@ public final class SignalServiceProtos { */ org.session.libsignal.service.internal.push.SignalServiceProtos.ConfigurationMessageOrBuilder getConfigurationMessageOrBuilder(); - // optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + // optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ boolean hasDataExtractionNotification(); /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification getDataExtractionNotification(); /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotificationOrBuilder getDataExtractionNotificationOrBuilder(); } @@ -1882,7 +1882,7 @@ public final class SignalServiceProtos { bitField0_ |= 0x00000008; break; } - case 658: { + case 66: { org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification.Builder subBuilder = null; if (((bitField0_ & 0x00000010) == 0x00000010)) { subBuilder = dataExtractionNotification_.toBuilder(); @@ -2023,23 +2023,23 @@ public final class SignalServiceProtos { return configurationMessage_; } - // optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; - public static final int DATAEXTRACTIONNOTIFICATION_FIELD_NUMBER = 82; + // optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; + public static final int DATAEXTRACTIONNOTIFICATION_FIELD_NUMBER = 8; private org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification dataExtractionNotification_; /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ public boolean hasDataExtractionNotification() { return ((bitField0_ & 0x00000010) == 0x00000010); } /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ public org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification getDataExtractionNotification() { return dataExtractionNotification_; } /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ public org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotificationOrBuilder getDataExtractionNotificationOrBuilder() { return dataExtractionNotification_; @@ -2107,7 +2107,7 @@ public final class SignalServiceProtos { output.writeMessage(7, configurationMessage_); } if (((bitField0_ & 0x00000010) == 0x00000010)) { - output.writeMessage(82, dataExtractionNotification_); + output.writeMessage(8, dataExtractionNotification_); } getUnknownFields().writeTo(output); } @@ -2136,7 +2136,7 @@ public final class SignalServiceProtos { } if (((bitField0_ & 0x00000010) == 0x00000010)) { size += com.google.protobuf.CodedOutputStream - .computeMessageSize(82, dataExtractionNotification_); + .computeMessageSize(8, dataExtractionNotification_); } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; @@ -2913,18 +2913,18 @@ public final class SignalServiceProtos { return configurationMessageBuilder_; } - // optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + // optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; private org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification dataExtractionNotification_ = org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification.getDefaultInstance(); private com.google.protobuf.SingleFieldBuilder< org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification, org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification.Builder, org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotificationOrBuilder> dataExtractionNotificationBuilder_; /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ public boolean hasDataExtractionNotification() { return ((bitField0_ & 0x00000010) == 0x00000010); } /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ public org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification getDataExtractionNotification() { if (dataExtractionNotificationBuilder_ == null) { @@ -2934,7 +2934,7 @@ public final class SignalServiceProtos { } } /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ public Builder setDataExtractionNotification(org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification value) { if (dataExtractionNotificationBuilder_ == null) { @@ -2950,7 +2950,7 @@ public final class SignalServiceProtos { return this; } /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ public Builder setDataExtractionNotification( org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification.Builder builderForValue) { @@ -2964,7 +2964,7 @@ public final class SignalServiceProtos { return this; } /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ public Builder mergeDataExtractionNotification(org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification value) { if (dataExtractionNotificationBuilder_ == null) { @@ -2983,7 +2983,7 @@ public final class SignalServiceProtos { return this; } /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ public Builder clearDataExtractionNotification() { if (dataExtractionNotificationBuilder_ == null) { @@ -2996,7 +2996,7 @@ public final class SignalServiceProtos { return this; } /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ public org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification.Builder getDataExtractionNotificationBuilder() { bitField0_ |= 0x00000010; @@ -3004,7 +3004,7 @@ public final class SignalServiceProtos { return getDataExtractionNotificationFieldBuilder().getBuilder(); } /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ public org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotificationOrBuilder getDataExtractionNotificationOrBuilder() { if (dataExtractionNotificationBuilder_ != null) { @@ -3014,7 +3014,7 @@ public final class SignalServiceProtos { } } /** - * optional .signalservice.DataExtractionNotification dataExtractionNotification = 82; + * optional .signalservice.DataExtractionNotification dataExtractionNotification = 8; */ private com.google.protobuf.SingleFieldBuilder< org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification, org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotification.Builder, org.session.libsignal.service.internal.push.SignalServiceProtos.DataExtractionNotificationOrBuilder> @@ -4370,6 +4370,20 @@ public final class SignalServiceProtos { */ org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.LokiProfileOrBuilder getProfileOrBuilder(); + // optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + boolean hasOpenGroupInvitation(); + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation getOpenGroupInvitation(); + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitationOrBuilder getOpenGroupInvitationOrBuilder(); + // optional .signalservice.DataMessage.ClosedGroupControlMessage closedGroupControlMessage = 104; /** * optional .signalservice.DataMessage.ClosedGroupControlMessage closedGroupControlMessage = 104; @@ -4530,9 +4544,22 @@ public final class SignalServiceProtos { bitField0_ |= 0x00000080; break; } + case 818: { + org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.Builder subBuilder = null; + if (((bitField0_ & 0x00000100) == 0x00000100)) { + subBuilder = openGroupInvitation_.toBuilder(); + } + openGroupInvitation_ = input.readMessage(org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(openGroupInvitation_); + openGroupInvitation_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000100; + break; + } case 834: { org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.ClosedGroupControlMessage.Builder subBuilder = null; - if (((bitField0_ & 0x00000100) == 0x00000100)) { + if (((bitField0_ & 0x00000200) == 0x00000200)) { subBuilder = closedGroupControlMessage_.toBuilder(); } closedGroupControlMessage_ = input.readMessage(org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.ClosedGroupControlMessage.PARSER, extensionRegistry); @@ -4540,11 +4567,11 @@ public final class SignalServiceProtos { subBuilder.mergeFrom(closedGroupControlMessage_); closedGroupControlMessage_ = subBuilder.buildPartial(); } - bitField0_ |= 0x00000100; + bitField0_ |= 0x00000200; break; } case 842: { - bitField0_ |= 0x00000200; + bitField0_ |= 0x00000400; syncTarget_ = input.readBytes(); break; } @@ -8343,6 +8370,745 @@ public final class SignalServiceProtos { // @@protoc_insertion_point(class_scope:signalservice.DataMessage.LokiProfile) } + public interface OpenGroupInvitationOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // required string url = 1; + /** + * required string url = 1; + * + *
+       * @required
+       * 
+ */ + boolean hasUrl(); + /** + * required string url = 1; + * + *
+       * @required
+       * 
+ */ + java.lang.String getUrl(); + /** + * required string url = 1; + * + *
+       * @required
+       * 
+ */ + com.google.protobuf.ByteString + getUrlBytes(); + + // required string name = 3; + /** + * required string name = 3; + * + *
+       * @required
+       * 
+ */ + boolean hasName(); + /** + * required string name = 3; + * + *
+       * @required
+       * 
+ */ + java.lang.String getName(); + /** + * required string name = 3; + * + *
+       * @required
+       * 
+ */ + com.google.protobuf.ByteString + getNameBytes(); + } + /** + * Protobuf type {@code signalservice.DataMessage.OpenGroupInvitation} + */ + public static final class OpenGroupInvitation extends + com.google.protobuf.GeneratedMessage + implements OpenGroupInvitationOrBuilder { + // Use OpenGroupInvitation.newBuilder() to construct. + private OpenGroupInvitation(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private OpenGroupInvitation(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final OpenGroupInvitation defaultInstance; + public static OpenGroupInvitation getDefaultInstance() { + return defaultInstance; + } + + public OpenGroupInvitation getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private OpenGroupInvitation( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + bitField0_ |= 0x00000001; + url_ = input.readBytes(); + break; + } + case 26: { + bitField0_ |= 0x00000002; + name_ = input.readBytes(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.session.libsignal.service.internal.push.SignalServiceProtos.internal_static_signalservice_DataMessage_OpenGroupInvitation_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.session.libsignal.service.internal.push.SignalServiceProtos.internal_static_signalservice_DataMessage_OpenGroupInvitation_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.class, org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public OpenGroupInvitation parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new OpenGroupInvitation(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + // required string url = 1; + public static final int URL_FIELD_NUMBER = 1; + private java.lang.Object url_; + /** + * required string url = 1; + * + *
+       * @required
+       * 
+ */ + public boolean hasUrl() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string url = 1; + * + *
+       * @required
+       * 
+ */ + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + url_ = s; + } + return s; + } + } + /** + * required string url = 1; + * + *
+       * @required
+       * 
+ */ + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + // required string name = 3; + public static final int NAME_FIELD_NUMBER = 3; + private java.lang.Object name_; + /** + * required string name = 3; + * + *
+       * @required
+       * 
+ */ + public boolean hasName() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string name = 3; + * + *
+       * @required
+       * 
+ */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + name_ = s; + } + return s; + } + } + /** + * required string name = 3; + * + *
+       * @required
+       * 
+ */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private void initFields() { + url_ = ""; + name_ = ""; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!hasUrl()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasName()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getUrlBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(3, getNameBytes()); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getUrlBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getNameBytes()); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code signalservice.DataMessage.OpenGroupInvitation} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitationOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.session.libsignal.service.internal.push.SignalServiceProtos.internal_static_signalservice_DataMessage_OpenGroupInvitation_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.session.libsignal.service.internal.push.SignalServiceProtos.internal_static_signalservice_DataMessage_OpenGroupInvitation_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.class, org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.Builder.class); + } + + // Construct using org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + url_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + name_ = ""; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.session.libsignal.service.internal.push.SignalServiceProtos.internal_static_signalservice_DataMessage_OpenGroupInvitation_descriptor; + } + + public org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation getDefaultInstanceForType() { + return org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.getDefaultInstance(); + } + + public org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation build() { + org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation buildPartial() { + org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation result = new org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.url_ = url_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.name_ = name_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation) { + return mergeFrom((org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation other) { + if (other == org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.getDefaultInstance()) return this; + if (other.hasUrl()) { + bitField0_ |= 0x00000001; + url_ = other.url_; + onChanged(); + } + if (other.hasName()) { + bitField0_ |= 0x00000002; + name_ = other.name_; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!hasUrl()) { + + return false; + } + if (!hasName()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // required string url = 1; + private java.lang.Object url_ = ""; + /** + * required string url = 1; + * + *
+         * @required
+         * 
+ */ + public boolean hasUrl() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string url = 1; + * + *
+         * @required
+         * 
+ */ + public java.lang.String getUrl() { + java.lang.Object ref = url_; + if (!(ref instanceof java.lang.String)) { + java.lang.String s = ((com.google.protobuf.ByteString) ref) + .toStringUtf8(); + url_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string url = 1; + * + *
+         * @required
+         * 
+ */ + public com.google.protobuf.ByteString + getUrlBytes() { + java.lang.Object ref = url_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + url_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string url = 1; + * + *
+         * @required
+         * 
+ */ + public Builder setUrl( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + url_ = value; + onChanged(); + return this; + } + /** + * required string url = 1; + * + *
+         * @required
+         * 
+ */ + public Builder clearUrl() { + bitField0_ = (bitField0_ & ~0x00000001); + url_ = getDefaultInstance().getUrl(); + onChanged(); + return this; + } + /** + * required string url = 1; + * + *
+         * @required
+         * 
+ */ + public Builder setUrlBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + url_ = value; + onChanged(); + return this; + } + + // required string name = 3; + private java.lang.Object name_ = ""; + /** + * required string name = 3; + * + *
+         * @required
+         * 
+ */ + public boolean hasName() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required string name = 3; + * + *
+         * @required
+         * 
+ */ + public java.lang.String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof java.lang.String)) { + java.lang.String s = ((com.google.protobuf.ByteString) ref) + .toStringUtf8(); + name_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string name = 3; + * + *
+         * @required
+         * 
+ */ + public com.google.protobuf.ByteString + getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string name = 3; + * + *
+         * @required
+         * 
+ */ + public Builder setName( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + name_ = value; + onChanged(); + return this; + } + /** + * required string name = 3; + * + *
+         * @required
+         * 
+ */ + public Builder clearName() { + bitField0_ = (bitField0_ & ~0x00000002); + name_ = getDefaultInstance().getName(); + onChanged(); + return this; + } + /** + * required string name = 3; + * + *
+         * @required
+         * 
+ */ + public Builder setNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + name_ = value; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:signalservice.DataMessage.OpenGroupInvitation) + } + + static { + defaultInstance = new OpenGroupInvitation(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:signalservice.DataMessage.OpenGroupInvitation) + } + public interface ClosedGroupControlMessageOrBuilder extends com.google.protobuf.MessageOrBuilder { @@ -10873,6 +11639,28 @@ public final class SignalServiceProtos { return profile_; } + // optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + public static final int OPENGROUPINVITATION_FIELD_NUMBER = 102; + private org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation openGroupInvitation_; + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + public boolean hasOpenGroupInvitation() { + return ((bitField0_ & 0x00000100) == 0x00000100); + } + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + public org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation getOpenGroupInvitation() { + return openGroupInvitation_; + } + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + public org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitationOrBuilder getOpenGroupInvitationOrBuilder() { + return openGroupInvitation_; + } + // optional .signalservice.DataMessage.ClosedGroupControlMessage closedGroupControlMessage = 104; public static final int CLOSEDGROUPCONTROLMESSAGE_FIELD_NUMBER = 104; private org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.ClosedGroupControlMessage closedGroupControlMessage_; @@ -10880,7 +11668,7 @@ public final class SignalServiceProtos { * optional .signalservice.DataMessage.ClosedGroupControlMessage closedGroupControlMessage = 104; */ public boolean hasClosedGroupControlMessage() { - return ((bitField0_ & 0x00000100) == 0x00000100); + return ((bitField0_ & 0x00000200) == 0x00000200); } /** * optional .signalservice.DataMessage.ClosedGroupControlMessage closedGroupControlMessage = 104; @@ -10902,7 +11690,7 @@ public final class SignalServiceProtos { * optional string syncTarget = 105; */ public boolean hasSyncTarget() { - return ((bitField0_ & 0x00000200) == 0x00000200); + return ((bitField0_ & 0x00000400) == 0x00000400); } /** * optional string syncTarget = 105; @@ -10949,6 +11737,7 @@ public final class SignalServiceProtos { quote_ = org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.Quote.getDefaultInstance(); preview_ = java.util.Collections.emptyList(); profile_ = org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.LokiProfile.getDefaultInstance(); + openGroupInvitation_ = org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.getDefaultInstance(); closedGroupControlMessage_ = org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.ClosedGroupControlMessage.getDefaultInstance(); syncTarget_ = ""; } @@ -10981,6 +11770,12 @@ public final class SignalServiceProtos { return false; } } + if (hasOpenGroupInvitation()) { + if (!getOpenGroupInvitation().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } if (hasClosedGroupControlMessage()) { if (!getClosedGroupControlMessage().isInitialized()) { memoizedIsInitialized = 0; @@ -11025,9 +11820,12 @@ public final class SignalServiceProtos { output.writeMessage(101, profile_); } if (((bitField0_ & 0x00000100) == 0x00000100)) { - output.writeMessage(104, closedGroupControlMessage_); + output.writeMessage(102, openGroupInvitation_); } if (((bitField0_ & 0x00000200) == 0x00000200)) { + output.writeMessage(104, closedGroupControlMessage_); + } + if (((bitField0_ & 0x00000400) == 0x00000400)) { output.writeBytes(105, getSyncTargetBytes()); } getUnknownFields().writeTo(output); @@ -11081,9 +11879,13 @@ public final class SignalServiceProtos { } if (((bitField0_ & 0x00000100) == 0x00000100)) { size += com.google.protobuf.CodedOutputStream - .computeMessageSize(104, closedGroupControlMessage_); + .computeMessageSize(102, openGroupInvitation_); } if (((bitField0_ & 0x00000200) == 0x00000200)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(104, closedGroupControlMessage_); + } + if (((bitField0_ & 0x00000400) == 0x00000400)) { size += com.google.protobuf.CodedOutputStream .computeBytesSize(105, getSyncTargetBytes()); } @@ -11200,6 +12002,7 @@ public final class SignalServiceProtos { getQuoteFieldBuilder(); getPreviewFieldBuilder(); getProfileFieldBuilder(); + getOpenGroupInvitationFieldBuilder(); getClosedGroupControlMessageFieldBuilder(); } } @@ -11249,14 +12052,20 @@ public final class SignalServiceProtos { profileBuilder_.clear(); } bitField0_ = (bitField0_ & ~0x00000200); + if (openGroupInvitationBuilder_ == null) { + openGroupInvitation_ = org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.getDefaultInstance(); + } else { + openGroupInvitationBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000400); if (closedGroupControlMessageBuilder_ == null) { closedGroupControlMessage_ = org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.ClosedGroupControlMessage.getDefaultInstance(); } else { closedGroupControlMessageBuilder_.clear(); } - bitField0_ = (bitField0_ & ~0x00000400); - syncTarget_ = ""; bitField0_ = (bitField0_ & ~0x00000800); + syncTarget_ = ""; + bitField0_ = (bitField0_ & ~0x00001000); return this; } @@ -11350,13 +12159,21 @@ public final class SignalServiceProtos { if (((from_bitField0_ & 0x00000400) == 0x00000400)) { to_bitField0_ |= 0x00000100; } + if (openGroupInvitationBuilder_ == null) { + result.openGroupInvitation_ = openGroupInvitation_; + } else { + result.openGroupInvitation_ = openGroupInvitationBuilder_.build(); + } + if (((from_bitField0_ & 0x00000800) == 0x00000800)) { + to_bitField0_ |= 0x00000200; + } if (closedGroupControlMessageBuilder_ == null) { result.closedGroupControlMessage_ = closedGroupControlMessage_; } else { result.closedGroupControlMessage_ = closedGroupControlMessageBuilder_.build(); } - if (((from_bitField0_ & 0x00000800) == 0x00000800)) { - to_bitField0_ |= 0x00000200; + if (((from_bitField0_ & 0x00001000) == 0x00001000)) { + to_bitField0_ |= 0x00000400; } result.syncTarget_ = syncTarget_; result.bitField0_ = to_bitField0_; @@ -11453,11 +12270,14 @@ public final class SignalServiceProtos { if (other.hasProfile()) { mergeProfile(other.getProfile()); } + if (other.hasOpenGroupInvitation()) { + mergeOpenGroupInvitation(other.getOpenGroupInvitation()); + } if (other.hasClosedGroupControlMessage()) { mergeClosedGroupControlMessage(other.getClosedGroupControlMessage()); } if (other.hasSyncTarget()) { - bitField0_ |= 0x00000800; + bitField0_ |= 0x00001000; syncTarget_ = other.syncTarget_; onChanged(); } @@ -11490,6 +12310,12 @@ public final class SignalServiceProtos { return false; } } + if (hasOpenGroupInvitation()) { + if (!getOpenGroupInvitation().isInitialized()) { + + return false; + } + } if (hasClosedGroupControlMessage()) { if (!getClosedGroupControlMessage().isInitialized()) { @@ -12558,6 +13384,123 @@ public final class SignalServiceProtos { return profileBuilder_; } + // optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + private org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation openGroupInvitation_ = org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation, org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.Builder, org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitationOrBuilder> openGroupInvitationBuilder_; + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + public boolean hasOpenGroupInvitation() { + return ((bitField0_ & 0x00000400) == 0x00000400); + } + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + public org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation getOpenGroupInvitation() { + if (openGroupInvitationBuilder_ == null) { + return openGroupInvitation_; + } else { + return openGroupInvitationBuilder_.getMessage(); + } + } + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + public Builder setOpenGroupInvitation(org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation value) { + if (openGroupInvitationBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + openGroupInvitation_ = value; + onChanged(); + } else { + openGroupInvitationBuilder_.setMessage(value); + } + bitField0_ |= 0x00000400; + return this; + } + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + public Builder setOpenGroupInvitation( + org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.Builder builderForValue) { + if (openGroupInvitationBuilder_ == null) { + openGroupInvitation_ = builderForValue.build(); + onChanged(); + } else { + openGroupInvitationBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000400; + return this; + } + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + public Builder mergeOpenGroupInvitation(org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation value) { + if (openGroupInvitationBuilder_ == null) { + if (((bitField0_ & 0x00000400) == 0x00000400) && + openGroupInvitation_ != org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.getDefaultInstance()) { + openGroupInvitation_ = + org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.newBuilder(openGroupInvitation_).mergeFrom(value).buildPartial(); + } else { + openGroupInvitation_ = value; + } + onChanged(); + } else { + openGroupInvitationBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000400; + return this; + } + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + public Builder clearOpenGroupInvitation() { + if (openGroupInvitationBuilder_ == null) { + openGroupInvitation_ = org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.getDefaultInstance(); + onChanged(); + } else { + openGroupInvitationBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000400); + return this; + } + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + public org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.Builder getOpenGroupInvitationBuilder() { + bitField0_ |= 0x00000400; + onChanged(); + return getOpenGroupInvitationFieldBuilder().getBuilder(); + } + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + public org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitationOrBuilder getOpenGroupInvitationOrBuilder() { + if (openGroupInvitationBuilder_ != null) { + return openGroupInvitationBuilder_.getMessageOrBuilder(); + } else { + return openGroupInvitation_; + } + } + /** + * optional .signalservice.DataMessage.OpenGroupInvitation openGroupInvitation = 102; + */ + private com.google.protobuf.SingleFieldBuilder< + org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation, org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.Builder, org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitationOrBuilder> + getOpenGroupInvitationFieldBuilder() { + if (openGroupInvitationBuilder_ == null) { + openGroupInvitationBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation, org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitation.Builder, org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.OpenGroupInvitationOrBuilder>( + openGroupInvitation_, + getParentForChildren(), + isClean()); + openGroupInvitation_ = null; + } + return openGroupInvitationBuilder_; + } + // optional .signalservice.DataMessage.ClosedGroupControlMessage closedGroupControlMessage = 104; private org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.ClosedGroupControlMessage closedGroupControlMessage_ = org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.ClosedGroupControlMessage.getDefaultInstance(); private com.google.protobuf.SingleFieldBuilder< @@ -12566,7 +13509,7 @@ public final class SignalServiceProtos { * optional .signalservice.DataMessage.ClosedGroupControlMessage closedGroupControlMessage = 104; */ public boolean hasClosedGroupControlMessage() { - return ((bitField0_ & 0x00000400) == 0x00000400); + return ((bitField0_ & 0x00000800) == 0x00000800); } /** * optional .signalservice.DataMessage.ClosedGroupControlMessage closedGroupControlMessage = 104; @@ -12591,7 +13534,7 @@ public final class SignalServiceProtos { } else { closedGroupControlMessageBuilder_.setMessage(value); } - bitField0_ |= 0x00000400; + bitField0_ |= 0x00000800; return this; } /** @@ -12605,7 +13548,7 @@ public final class SignalServiceProtos { } else { closedGroupControlMessageBuilder_.setMessage(builderForValue.build()); } - bitField0_ |= 0x00000400; + bitField0_ |= 0x00000800; return this; } /** @@ -12613,7 +13556,7 @@ public final class SignalServiceProtos { */ public Builder mergeClosedGroupControlMessage(org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.ClosedGroupControlMessage value) { if (closedGroupControlMessageBuilder_ == null) { - if (((bitField0_ & 0x00000400) == 0x00000400) && + if (((bitField0_ & 0x00000800) == 0x00000800) && closedGroupControlMessage_ != org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.ClosedGroupControlMessage.getDefaultInstance()) { closedGroupControlMessage_ = org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.ClosedGroupControlMessage.newBuilder(closedGroupControlMessage_).mergeFrom(value).buildPartial(); @@ -12624,7 +13567,7 @@ public final class SignalServiceProtos { } else { closedGroupControlMessageBuilder_.mergeFrom(value); } - bitField0_ |= 0x00000400; + bitField0_ |= 0x00000800; return this; } /** @@ -12637,14 +13580,14 @@ public final class SignalServiceProtos { } else { closedGroupControlMessageBuilder_.clear(); } - bitField0_ = (bitField0_ & ~0x00000400); + bitField0_ = (bitField0_ & ~0x00000800); return this; } /** * optional .signalservice.DataMessage.ClosedGroupControlMessage closedGroupControlMessage = 104; */ public org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage.ClosedGroupControlMessage.Builder getClosedGroupControlMessageBuilder() { - bitField0_ |= 0x00000400; + bitField0_ |= 0x00000800; onChanged(); return getClosedGroupControlMessageFieldBuilder().getBuilder(); } @@ -12681,7 +13624,7 @@ public final class SignalServiceProtos { * optional string syncTarget = 105; */ public boolean hasSyncTarget() { - return ((bitField0_ & 0x00000800) == 0x00000800); + return ((bitField0_ & 0x00001000) == 0x00001000); } /** * optional string syncTarget = 105; @@ -12721,7 +13664,7 @@ public final class SignalServiceProtos { if (value == null) { throw new NullPointerException(); } - bitField0_ |= 0x00000800; + bitField0_ |= 0x00001000; syncTarget_ = value; onChanged(); return this; @@ -12730,7 +13673,7 @@ public final class SignalServiceProtos { * optional string syncTarget = 105; */ public Builder clearSyncTarget() { - bitField0_ = (bitField0_ & ~0x00000800); + bitField0_ = (bitField0_ & ~0x00001000); syncTarget_ = getDefaultInstance().getSyncTarget(); onChanged(); return this; @@ -12743,7 +13686,7 @@ public final class SignalServiceProtos { if (value == null) { throw new NullPointerException(); } - bitField0_ |= 0x00000800; + bitField0_ |= 0x00001000; syncTarget_ = value; onChanged(); return this; @@ -20189,6 +21132,11 @@ public final class SignalServiceProtos { private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_signalservice_DataMessage_LokiProfile_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_signalservice_DataMessage_OpenGroupInvitation_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_signalservice_DataMessage_OpenGroupInvitation_fieldAccessorTable; private static com.google.protobuf.Descriptors.Descriptor internal_static_signalservice_DataMessage_ClosedGroupControlMessage_descriptor; private static @@ -20253,14 +21201,14 @@ public final class SignalServiceProtos { "tMessage\0223\n\rtypingMessage\030\006 \001(\0132\034.signal" + "service.TypingMessage\022A\n\024configurationMe" + "ssage\030\007 \001(\0132#.signalservice.Configuratio" + - "nMessage\022M\n\032dataExtractionNotification\030R" + + "nMessage\022M\n\032dataExtractionNotification\030\010" + " \001(\0132).signalservice.DataExtractionNotif" + "ication\"0\n\007KeyPair\022\021\n\tpublicKey\030\001 \002(\014\022\022\n" + "\nprivateKey\030\002 \002(\014\"\226\001\n\032DataExtractionNoti" + "fication\022<\n\004type\030\001 \002(\0162..signalservice.D", "ataExtractionNotification.Type\022\021\n\ttimest" + "amp\030\002 \001(\004\"\'\n\004Type\022\016\n\nSCREENSHOT\020\001\022\017\n\013MED" + - "IA_SAVED\020\002\"\215\013\n\013DataMessage\022\014\n\004body\030\001 \001(\t" + + "IA_SAVED\020\002\"\214\014\n\013DataMessage\022\014\n\004body\030\001 \001(\t" + "\0225\n\013attachments\030\002 \003(\0132 .signalservice.At" + "tachmentPointer\022*\n\005group\030\003 \001(\0132\033.signals" + "ervice.GroupContext\022\r\n\005flags\030\004 \001(\r\022\023\n\013ex" + @@ -20269,62 +21217,65 @@ public final class SignalServiceProtos { "rvice.DataMessage.Quote\0223\n\007preview\030\n \003(\013" + "2\".signalservice.DataMessage.Preview\0227\n\007", "profile\030e \001(\0132&.signalservice.DataMessag" + - "e.LokiProfile\022W\n\031closedGroupControlMessa" + - "ge\030h \001(\01324.signalservice.DataMessage.Clo" + - "sedGroupControlMessage\022\022\n\nsyncTarget\030i \001" + - "(\t\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\013attachments\030\004 \003(\01321.si" + - "gnalservice.DataMessage.Quote.QuotedAtta" + - "chment\032\231\001\n\020QuotedAttachment\022\023\n\013contentTy" + - "pe\030\001 \001(\t\022\020\n\010fileName\030\002 \001(\t\0223\n\tthumbnail\030" + - "\003 \001(\0132 .signalservice.AttachmentPointer\022", - "\r\n\005flags\030\004 \001(\r\"\032\n\005Flags\022\021\n\rVOICE_MESSAGE" + - "\020\001\032V\n\007Preview\022\013\n\003url\030\001 \002(\t\022\r\n\005title\030\002 \001(" + - "\t\022/\n\005image\030\003 \001(\0132 .signalservice.Attachm" + - "entPointer\032:\n\013LokiProfile\022\023\n\013displayName" + - "\030\001 \001(\t\022\026\n\016profilePicture\030\002 \001(\t\032\343\003\n\031Close" + - "dGroupControlMessage\022G\n\004type\030\001 \002(\01629.sig" + - "nalservice.DataMessage.ClosedGroupContro" + - "lMessage.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.sign" + - "alservice.KeyPair\022\017\n\007members\030\005 \003(\014\022\016\n\006ad", - "mins\030\006 \003(\014\022U\n\010wrappers\030\007 \003(\0132C.signalser" + - "vice.DataMessage.ClosedGroupControlMessa" + - "ge.KeyPairWrapper\032=\n\016KeyPairWrapper\022\021\n\tp" + - "ublicKey\030\001 \002(\014\022\030\n\020encryptedKeyPair\030\002 \002(\014" + - "\"r\n\004Type\022\007\n\003NEW\020\001\022\027\n\023ENCRYPTION_KEY_PAIR" + - "\020\003\022\017\n\013NAME_CHANGE\020\004\022\021\n\rMEMBERS_ADDED\020\005\022\023" + - "\n\017MEMBERS_REMOVED\020\006\022\017\n\013MEMBER_LEFT\020\007\"$\n\005" + - "Flags\022\033\n\027EXPIRATION_TIMER_UPDATE\020\002\"\316\003\n\024C" + - "onfigurationMessage\022E\n\014closedGroups\030\001 \003(" + - "\0132/.signalservice.ConfigurationMessage.C", - "losedGroup\022\022\n\nopenGroups\030\002 \003(\t\022\023\n\013displa" + - "yName\030\003 \001(\t\022\026\n\016profilePicture\030\004 \001(\t\022\022\n\np" + - "rofileKey\030\005 \001(\014\022=\n\010contacts\030\006 \003(\0132+.sign" + - "alservice.ConfigurationMessage.Contact\032\202" + - "\001\n\013ClosedGroup\022\021\n\tpublicKey\030\001 \001(\014\022\014\n\004nam" + - "e\030\002 \001(\t\0221\n\021encryptionKeyPair\030\003 \001(\0132\026.sig" + - "nalservice.KeyPair\022\017\n\007members\030\004 \003(\014\022\016\n\006a" + - "dmins\030\005 \003(\014\032V\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\nprofileKey\030\004 \001(\014\"u\n\016ReceiptMessage\0220\n", - "\004type\030\001 \002(\0162\".signalservice.ReceiptMessa" + - "ge.Type\022\021\n\ttimestamp\030\002 \003(\004\"\036\n\004Type\022\014\n\010DE" + - "LIVERY\020\000\022\010\n\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\004size\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\005fla" + - "gs\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\013 \001(\t\022\013\n\003url\030e \001(\t\"\032\n\005Flags\022\021" + - "\n\rVOICE_MESSAGE\020\001\"\365\001\n\014GroupContext\022\n\n\002id" + - "\030\001 \001(\014\022.\n\004type\030\002 \001(\0162 .signalservice.Gro", - "upContext.Type\022\014\n\004name\030\003 \001(\t\022\017\n\007members\030" + - "\004 \003(\t\0220\n\006avatar\030\005 \001(\0132 .signalservice.At" + - "tachmentPointer\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\014REQUEST_INFO\020\004BB\n+org.session" + - ".libsignal.service.internal.pushB\023Signal" + - "ServiceProtos" + "e.LokiProfile\022K\n\023openGroupInvitation\030f \001" + + "(\0132..signalservice.DataMessage.OpenGroup" + + "Invitation\022W\n\031closedGroupControlMessage\030" + + "h \001(\01324.signalservice.DataMessage.Closed" + + "GroupControlMessage\022\022\n\nsyncTarget\030i \001(\t\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\013attachments\030\004 \003(\01321.signa" + + "lservice.DataMessage.Quote.QuotedAttachm" + + "ent\032\231\001\n\020QuotedAttachment\022\023\n\013contentType\030", + "\001 \001(\t\022\020\n\010fileName\030\002 \001(\t\0223\n\tthumbnail\030\003 \001" + + "(\0132 .signalservice.AttachmentPointer\022\r\n\005" + + "flags\030\004 \001(\r\"\032\n\005Flags\022\021\n\rVOICE_MESSAGE\020\001\032" + + "V\n\007Preview\022\013\n\003url\030\001 \002(\t\022\r\n\005title\030\002 \001(\t\022/" + + "\n\005image\030\003 \001(\0132 .signalservice.Attachment" + + "Pointer\032:\n\013LokiProfile\022\023\n\013displayName\030\001 " + + "\001(\t\022\026\n\016profilePicture\030\002 \001(\t\0320\n\023OpenGroup" + + "Invitation\022\013\n\003url\030\001 \002(\t\022\014\n\004name\030\003 \002(\t\032\343\003" + + "\n\031ClosedGroupControlMessage\022G\n\004type\030\001 \002(" + + "\01629.signalservice.DataMessage.ClosedGrou", + "pControlMessage.Type\022\021\n\tpublicKey\030\002 \001(\014\022" + + "\014\n\004name\030\003 \001(\t\0221\n\021encryptionKeyPair\030\004 \001(\013" + + "2\026.signalservice.KeyPair\022\017\n\007members\030\005 \003(" + + "\014\022\016\n\006admins\030\006 \003(\014\022U\n\010wrappers\030\007 \003(\0132C.si" + + "gnalservice.DataMessage.ClosedGroupContr" + + "olMessage.KeyPairWrapper\032=\n\016KeyPairWrapp" + + "er\022\021\n\tpublicKey\030\001 \002(\014\022\030\n\020encryptedKeyPai" + + "r\030\002 \002(\014\"r\n\004Type\022\007\n\003NEW\020\001\022\027\n\023ENCRYPTION_K" + + "EY_PAIR\020\003\022\017\n\013NAME_CHANGE\020\004\022\021\n\rMEMBERS_AD" + + "DED\020\005\022\023\n\017MEMBERS_REMOVED\020\006\022\017\n\013MEMBER_LEF", + "T\020\007\"$\n\005Flags\022\033\n\027EXPIRATION_TIMER_UPDATE\020" + + "\002\"\316\003\n\024ConfigurationMessage\022E\n\014closedGrou" + + "ps\030\001 \003(\0132/.signalservice.ConfigurationMe" + + "ssage.ClosedGroup\022\022\n\nopenGroups\030\002 \003(\t\022\023\n" + + "\013displayName\030\003 \001(\t\022\026\n\016profilePicture\030\004 \001" + + "(\t\022\022\n\nprofileKey\030\005 \001(\014\022=\n\010contacts\030\006 \003(\013" + + "2+.signalservice.ConfigurationMessage.Co" + + "ntact\032\202\001\n\013ClosedGroup\022\021\n\tpublicKey\030\001 \001(\014" + + "\022\014\n\004name\030\002 \001(\t\0221\n\021encryptionKeyPair\030\003 \001(" + + "\0132\026.signalservice.KeyPair\022\017\n\007members\030\004 \003", + "(\014\022\016\n\006admins\030\005 \003(\014\032V\n\007Contact\022\021\n\tpublicK" + + "ey\030\001 \002(\014\022\014\n\004name\030\002 \002(\t\022\026\n\016profilePicture" + + "\030\003 \001(\t\022\022\n\nprofileKey\030\004 \001(\014\"u\n\016ReceiptMes" + + "sage\0220\n\004type\030\001 \002(\0162\".signalservice.Recei" + + "ptMessage.Type\022\021\n\ttimestamp\030\002 \003(\004\"\036\n\004Typ" + + "e\022\014\n\010DELIVERY\020\000\022\010\n\004READ\020\001\"\354\001\n\021Attachment" + + "Pointer\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\004size\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\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\005" + + "Flags\022\021\n\rVOICE_MESSAGE\020\001\"\365\001\n\014GroupContex" + + "t\022\n\n\002id\030\001 \001(\014\022.\n\004type\030\002 \001(\0162 .signalserv" + + "ice.GroupContext.Type\022\014\n\004name\030\003 \001(\t\022\017\n\007m" + + "embers\030\004 \003(\t\0220\n\006avatar\030\005 \001(\0132 .signalser" + + "vice.AttachmentPointer\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\007DELIV" + + "ER\020\002\022\010\n\004QUIT\020\003\022\020\n\014REQUEST_INFO\020\004BB\n+org." + + "session.libsignal.service.internal.pushB" + + "\023SignalServiceProtos" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -20366,7 +21317,7 @@ public final class SignalServiceProtos { internal_static_signalservice_DataMessage_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_DataMessage_descriptor, - new java.lang.String[] { "Body", "Attachments", "Group", "Flags", "ExpireTimer", "ProfileKey", "Timestamp", "Quote", "Preview", "Profile", "ClosedGroupControlMessage", "SyncTarget", }); + new java.lang.String[] { "Body", "Attachments", "Group", "Flags", "ExpireTimer", "ProfileKey", "Timestamp", "Quote", "Preview", "Profile", "OpenGroupInvitation", "ClosedGroupControlMessage", "SyncTarget", }); internal_static_signalservice_DataMessage_Quote_descriptor = internal_static_signalservice_DataMessage_descriptor.getNestedTypes().get(0); internal_static_signalservice_DataMessage_Quote_fieldAccessorTable = new @@ -20391,8 +21342,14 @@ public final class SignalServiceProtos { com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_DataMessage_LokiProfile_descriptor, new java.lang.String[] { "DisplayName", "ProfilePicture", }); - internal_static_signalservice_DataMessage_ClosedGroupControlMessage_descriptor = + internal_static_signalservice_DataMessage_OpenGroupInvitation_descriptor = internal_static_signalservice_DataMessage_descriptor.getNestedTypes().get(3); + internal_static_signalservice_DataMessage_OpenGroupInvitation_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_signalservice_DataMessage_OpenGroupInvitation_descriptor, + new java.lang.String[] { "Url", "Name", }); + internal_static_signalservice_DataMessage_ClosedGroupControlMessage_descriptor = + internal_static_signalservice_DataMessage_descriptor.getNestedTypes().get(4); internal_static_signalservice_DataMessage_ClosedGroupControlMessage_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_DataMessage_ClosedGroupControlMessage_descriptor,