From 7014f629feb0c5eff60e2e479f276e6829eb9486 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sun, 8 Mar 2026 11:55:19 +0100 Subject: [PATCH] Show member labels in listGroups command --- .../org/asamk/signal/manager/api/Group.java | 11 +-- .../asamk/signal/manager/api/GroupMember.java | 14 ++++ .../signal/manager/helper/GroupHelper.java | 8 +-- .../signal/manager/helper/SendHelper.java | 4 +- .../signal/manager/helper/SyncHelper.java | 2 +- .../manager/storage/groups/GroupInfo.java | 19 ++++-- .../manager/storage/groups/GroupInfoV1.java | 4 +- .../manager/storage/groups/GroupInfoV2.java | 25 +++---- .../storage/groups/GroupMemberInfo.java | 20 ++++++ .../storage/groups/GroupMemberInfoV1.java | 17 +++++ .../storage/groups/GroupMemberInfoV2.java | 38 +++++++++++ .../manager/storage/groups/GroupStore.java | 2 +- .../storage/prekeys/KyberPreKeyStore.java | 5 ++ .../signal/commands/ListGroupsCommand.java | 67 ++++++++++++++----- .../asamk/signal/dbus/DbusManagerImpl.java | 13 ++-- .../org/asamk/signal/dbus/DbusSignalImpl.java | 14 +++- .../signal-cli/reachability-metadata.json | 13 ++++ 17 files changed, 210 insertions(+), 66 deletions(-) create mode 100644 lib/src/main/java/org/asamk/signal/manager/api/GroupMember.java create mode 100644 lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupMemberInfo.java create mode 100644 lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupMemberInfoV1.java create mode 100644 lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupMemberInfoV2.java diff --git a/lib/src/main/java/org/asamk/signal/manager/api/Group.java b/lib/src/main/java/org/asamk/signal/manager/api/Group.java index 4d1fdaa1..fc668684 100644 --- a/lib/src/main/java/org/asamk/signal/manager/api/Group.java +++ b/lib/src/main/java/org/asamk/signal/manager/api/Group.java @@ -12,10 +12,9 @@ public record Group( String title, String description, GroupInviteLinkUrl groupInviteLinkUrl, - Set members, + Set members, Set pendingMembers, Set requestingMembers, - Set adminMembers, Set bannedMembers, boolean isBlocked, int messageExpirationTimer, @@ -37,8 +36,7 @@ public record Group( groupInfo.getGroupInviteLink(), groupInfo.getMembers() .stream() - .map(recipientStore::resolveRecipientAddress) - .map(org.asamk.signal.manager.storage.recipients.RecipientAddress::toApiRecipientAddress) + .map(m -> org.asamk.signal.manager.api.GroupMember.from(m, recipientStore)) .collect(Collectors.toSet()), groupInfo.getPendingMembers() .stream() @@ -50,11 +48,6 @@ public record Group( .map(recipientStore::resolveRecipientAddress) .map(org.asamk.signal.manager.storage.recipients.RecipientAddress::toApiRecipientAddress) .collect(Collectors.toSet()), - groupInfo.getAdminMembers() - .stream() - .map(recipientStore::resolveRecipientAddress) - .map(org.asamk.signal.manager.storage.recipients.RecipientAddress::toApiRecipientAddress) - .collect(Collectors.toSet()), groupInfo.getBannedMembers() .stream() .map(recipientStore::resolveRecipientAddress) diff --git a/lib/src/main/java/org/asamk/signal/manager/api/GroupMember.java b/lib/src/main/java/org/asamk/signal/manager/api/GroupMember.java new file mode 100644 index 00000000..239a597c --- /dev/null +++ b/lib/src/main/java/org/asamk/signal/manager/api/GroupMember.java @@ -0,0 +1,14 @@ +package org.asamk.signal.manager.api; + +import org.asamk.signal.manager.helper.RecipientAddressResolver; +import org.asamk.signal.manager.storage.groups.GroupMemberInfo; + +public record GroupMember( + RecipientAddress recipientAddress, boolean isAdmin, String labelEmoji, String label +) { + + public static GroupMember from(final GroupMemberInfo memberInfo, final RecipientAddressResolver recipientStore) { + return new GroupMember(recipientStore.resolveRecipientAddress(memberInfo.getRecipientId()) + .toApiRecipientAddress(), memberInfo.isAdmin(), memberInfo.labelEmoji(), memberInfo.labelString()); + } +} diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java index 516ff1e1..c4cb0a57 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/GroupHelper.java @@ -758,7 +758,7 @@ public class GroupHelper { if (admins != null) { final var newAdmins = new HashSet<>(admins); newAdmins.retainAll(group.getMembers()); - newAdmins.removeAll(group.getAdminMembers()); + newAdmins.removeAll(group.getAdminMemberRecipientIds()); if (!newAdmins.isEmpty()) { for (var admin : newAdmins) { var groupGroupChangePair = groupV2Helper.setMemberAdmin(group, admin, true); @@ -771,7 +771,7 @@ public class GroupHelper { if (removeAdmins != null) { final var existingRemoveAdmins = new HashSet<>(removeAdmins); - existingRemoveAdmins.retainAll(group.getAdminMembers()); + existingRemoveAdmins.retainAll(group.getAdminMemberRecipientIds()); if (!existingRemoveAdmins.isEmpty()) { for (var admin : existingRemoveAdmins) { var groupGroupChangePair = groupV2Helper.setMemberAdmin(group, admin, false); @@ -859,7 +859,7 @@ public class GroupHelper { final GroupInfoV2 groupInfoV2, final Set newAdmins ) throws LastGroupAdminException, IOException { - final var currentAdmins = groupInfoV2.getAdminMembers(); + final var currentAdmins = groupInfoV2.getAdminMemberRecipientIds(); newAdmins.removeAll(currentAdmins); newAdmins.retainAll(groupInfoV2.getMembers()); if (currentAdmins.contains(account.getSelfRecipientId()) @@ -888,7 +888,7 @@ public class GroupHelper { var group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.UPDATE) .withId(g.getGroupId().serialize()) .withName(g.name) - .withMembers(g.getMembers() + .withMembers(g.getMemberRecipientIds() .stream() .map(context.getRecipientHelper()::resolveSignalServiceAddress) .toList()); diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java index 10259350..20d74da9 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/SendHelper.java @@ -320,7 +320,9 @@ public class SendHelper { messageBuilder.withExpiration(g.getMessageExpirationTimer()); final var message = messageBuilder.build(); - final var recipients = includeSelf ? g.getMembers() : g.getMembersWithout(account.getSelfRecipientId()); + final var recipients = includeSelf + ? g.getMemberRecipientIds() + : g.getMembersWithout(account.getSelfRecipientId()); if (g.isAnnouncementGroup() && !g.isAdmin(account.getSelfRecipientId())) { if (message.getBody().isPresent() diff --git a/lib/src/main/java/org/asamk/signal/manager/helper/SyncHelper.java b/lib/src/main/java/org/asamk/signal/manager/helper/SyncHelper.java index fe369645..a13fc38f 100644 --- a/lib/src/main/java/org/asamk/signal/manager/helper/SyncHelper.java +++ b/lib/src/main/java/org/asamk/signal/manager/helper/SyncHelper.java @@ -114,7 +114,7 @@ public class SyncHelper { if (record instanceof GroupInfoV1 groupInfo) { out.write(new DeviceGroup(groupInfo.getGroupId().serialize(), Optional.ofNullable(groupInfo.name), - groupInfo.getMembers() + groupInfo.getMemberRecipientIds() .stream() .map(context.getRecipientHelper()::resolveSignalServiceAddress) .toList(), diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfo.java b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfo.java index 7de3a8f9..b6cf8688 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfo.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfo.java @@ -6,6 +6,7 @@ import org.asamk.signal.manager.api.GroupPermission; import org.asamk.signal.manager.storage.recipients.RecipientId; import org.whispersystems.signalservice.api.push.DistributionId; +import java.util.Collection; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -24,7 +25,11 @@ public sealed abstract class GroupInfo permits GroupInfoV1, GroupInfoV2 { public abstract GroupInviteLinkUrl getGroupInviteLink(); - public abstract Set getMembers(); + public abstract Collection getMembers(); + + public Set getMemberRecipientIds() { + return getMembers().stream().map(GroupMemberInfo::getRecipientId).collect(Collectors.toSet()); + } public Set getBannedMembers() { return Set.of(); @@ -38,7 +43,7 @@ public sealed abstract class GroupInfo permits GroupInfoV1, GroupInfoV2 { return Set.of(); } - public Set getAdminMembers() { + public Set getAdminMemberRecipientIds() { return Set.of(); } @@ -61,21 +66,23 @@ public sealed abstract class GroupInfo permits GroupInfoV1, GroupInfoV2 { public abstract GroupPermission getPermissionSendMessage(); public Set getMembersWithout(RecipientId recipientId) { - return getMembers().stream().filter(member -> !member.equals(recipientId)).collect(Collectors.toSet()); + return getMemberRecipientIds().stream() + .filter(member -> !member.equals(recipientId)) + .collect(Collectors.toSet()); } public Set getMembersIncludingPendingWithout(RecipientId recipientId) { - return Stream.concat(getMembers().stream(), getPendingMembers().stream()) + return Stream.concat(getMemberRecipientIds().stream(), getPendingMembers().stream()) .filter(member -> !member.equals(recipientId)) .collect(Collectors.toSet()); } public boolean isMember(RecipientId recipientId) { - return getMembers().contains(recipientId); + return getMembers().stream().anyMatch(m -> m.getRecipientId().equals(recipientId)); } public boolean isAdmin(RecipientId recipientId) { - return getAdminMembers().contains(recipientId); + return getMembers().stream().anyMatch(m -> m.isAdmin() && m.getRecipientId().equals(recipientId)); } public boolean isPendingMember(RecipientId recipientId) { diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV1.java b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV1.java index f377ff2d..2b601ed8 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV1.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV1.java @@ -80,8 +80,8 @@ public final class GroupInfoV1 extends GroupInfo { return null; } - public Set getMembers() { - return new HashSet<>(members); + public Collection getMembers() { + return members.stream().map(m -> (GroupMemberInfo) new GroupMemberInfoV1(m)).toList(); } @Override diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV2.java b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV2.java index dbb123c5..3616dceb 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV2.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupInfoV2.java @@ -3,18 +3,17 @@ package org.asamk.signal.manager.storage.groups; import org.asamk.signal.manager.api.GroupIdV2; import org.asamk.signal.manager.api.GroupInviteLinkUrl; import org.asamk.signal.manager.api.GroupPermission; -import org.asamk.signal.manager.storage.recipients.RecipientAddress; import org.asamk.signal.manager.storage.recipients.RecipientId; import org.asamk.signal.manager.storage.recipients.RecipientResolver; import org.signal.core.models.ServiceId; import org.signal.libsignal.zkgroup.groups.GroupMasterKey; import org.signal.storageservice.storage.protos.groups.AccessControl; -import org.signal.storageservice.storage.protos.groups.Member; import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup; import org.signal.storageservice.storage.protos.groups.local.EnabledState; import org.whispersystems.signalservice.api.push.DistributionId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; +import java.util.Collection; import java.util.Set; import java.util.stream.Collectors; @@ -122,14 +121,11 @@ public final class GroupInfoV2 extends GroupInfo { } @Override - public Set getMembers() { + public Collection getMembers() { if (this.group == null) { return Set.of(); } - return group.members.stream() - .map(m -> ServiceId.parseOrThrow(m.aciBytes)) - .map(recipientResolver::resolveRecipient) - .collect(Collectors.toSet()); + return group.members.stream().map(m -> (GroupMemberInfo) new GroupMemberInfoV2(m, recipientResolver)).toList(); } @Override @@ -175,16 +171,11 @@ public final class GroupInfoV2 extends GroupInfo { } @Override - public Set getAdminMembers() { - if (this.group == null) { - return Set.of(); - } - return group.members.stream() - .filter(m -> m.role == Member.Role.ADMINISTRATOR) - .map(m -> new RecipientAddress(ServiceId.ACI.parseOrNull(m.aciBytes), - ServiceId.PNI.parseOrNull(m.pniBytes), - null)) - .map(recipientResolver::resolveRecipient) + public Set getAdminMemberRecipientIds() { + return this.getMembers() + .stream() + .filter(GroupMemberInfo::isAdmin) + .map(GroupMemberInfo::getRecipientId) .collect(Collectors.toSet()); } diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupMemberInfo.java b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupMemberInfo.java new file mode 100644 index 00000000..d0d82c87 --- /dev/null +++ b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupMemberInfo.java @@ -0,0 +1,20 @@ +package org.asamk.signal.manager.storage.groups; + +import org.asamk.signal.manager.storage.recipients.RecipientId; + +public interface GroupMemberInfo { + + RecipientId getRecipientId(); + + default boolean isAdmin() { + return false; + } + + default String labelEmoji() { + return null; + } + + default String labelString() { + return null; + } +} diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupMemberInfoV1.java b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupMemberInfoV1.java new file mode 100644 index 00000000..c24661b4 --- /dev/null +++ b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupMemberInfoV1.java @@ -0,0 +1,17 @@ +package org.asamk.signal.manager.storage.groups; + +import org.asamk.signal.manager.storage.recipients.RecipientId; + +public class GroupMemberInfoV1 implements GroupMemberInfo { + + private final RecipientId recipientId; + + public GroupMemberInfoV1(final RecipientId recipientId) { + this.recipientId = recipientId; + } + + @Override + public RecipientId getRecipientId() { + return this.recipientId; + } +} diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupMemberInfoV2.java b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupMemberInfoV2.java new file mode 100644 index 00000000..88557ff1 --- /dev/null +++ b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupMemberInfoV2.java @@ -0,0 +1,38 @@ +package org.asamk.signal.manager.storage.groups; + +import org.asamk.signal.manager.storage.recipients.RecipientId; +import org.asamk.signal.manager.storage.recipients.RecipientResolver; +import org.signal.core.models.ServiceId; +import org.signal.storageservice.storage.protos.groups.Member; +import org.signal.storageservice.storage.protos.groups.local.DecryptedMember; + +public class GroupMemberInfoV2 implements GroupMemberInfo { + + private final RecipientResolver recipientResolver; + private final DecryptedMember member; + + public GroupMemberInfoV2(final DecryptedMember member, final RecipientResolver recipientResolver) { + this.recipientResolver = recipientResolver; + this.member = member; + } + + @Override + public RecipientId getRecipientId() { + return recipientResolver.resolveRecipient(ServiceId.ACI.parseOrThrow(member.aciBytes)); + } + + @Override + public boolean isAdmin() { + return member.role == Member.Role.ADMINISTRATOR; + } + + @Override + public String labelEmoji() { + return member.labelEmoji.isEmpty() ? null : member.labelEmoji; + } + + @Override + public String labelString() { + return member.labelString.isEmpty() ? null : member.labelString; + } +} diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupStore.java index f726b7f0..2c4bad99 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/groups/GroupStore.java @@ -648,7 +648,7 @@ public class GroupStore { ON CONFLICT (group_id, recipient_id) DO NOTHING """.formatted(TABLE_GROUP_V1_MEMBER); try (final var statement = connection.prepareStatement(sqlInsertMember)) { - for (final var recipient : groupV1.getMembers()) { + for (final var recipient : groupV1.getMemberRecipientIds()) { statement.setLong(1, internalId); statement.setLong(2, recipient.id()); statement.executeUpdate(); diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/prekeys/KyberPreKeyStore.java b/lib/src/main/java/org/asamk/signal/manager/storage/prekeys/KyberPreKeyStore.java index b6d79c2b..71892048 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/prekeys/KyberPreKeyStore.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/prekeys/KyberPreKeyStore.java @@ -133,6 +133,11 @@ public class KyberPreKeyStore implements SignalServiceKyberPreKeyStore { return getPreKey(keyId) != null; } + /** + * When we mark Kyber pre-keys used, we want to keep a record of last resort tuples, which are deleted when the key + * itself is deleted from this table via a cascading delete. + * For non-last-resort keys, this method just deletes them like normal. + */ @Override public void markKyberPreKeyUsed( final int kyberPreKeyId, diff --git a/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java b/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java index 77fe22eb..9084e907 100644 --- a/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java +++ b/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java @@ -1,5 +1,7 @@ package org.asamk.signal.commands; +import com.fasterxml.jackson.annotation.JsonInclude; + import net.sourceforge.argparse4j.impl.Arguments; import net.sourceforge.argparse4j.inf.Namespace; import net.sourceforge.argparse4j.inf.Subparser; @@ -7,6 +9,7 @@ import net.sourceforge.argparse4j.inf.Subparser; import org.asamk.signal.commands.exceptions.CommandException; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.api.Group; +import org.asamk.signal.manager.api.GroupMember; import org.asamk.signal.manager.api.RecipientAddress; import org.asamk.signal.output.JsonWriter; import org.asamk.signal.output.OutputWriter; @@ -37,33 +40,55 @@ public class ListGroupsCommand implements JsonRpcLocalCommand { subparser.addArgument("-g", "--group-id").help("Specify one or more group IDs to show.").nargs("*"); } - private static Set resolveMembers(Set addresses) { + private static Set resolveMembers(Set addresses) { + return addresses.stream() + .map(m -> m.recipientAddress().getLegacyIdentifier() + (m.isAdmin() ? "{ADMIN}" : "") + ( + m.labelEmoji() != null || m.label() != null ? "(" + ( + m.labelEmoji() != null ? m.labelEmoji() : "" + ) + ( + m.label() != null ? m.label() : "" + ) + ")" : "" + )) + .collect(Collectors.toSet()); + } + + private static Set resolveMemberAddress(Set addresses) { return addresses.stream().map(RecipientAddress::getLegacyIdentifier).collect(Collectors.toSet()); } - private static Set resolveJsonMembers(Set addresses) { + private static Set resolveJsonMembers(Set addresses) { return addresses.stream() - .map(address -> new JsonGroupMember(address.number().orElse(null), + .map(address -> new JsonGroupMemberAddress(address.number().orElse(null), address.uuid().map(UUID::toString).orElse(null))) .collect(Collectors.toSet()); } + private static Set resolveFullJsonMembers(Set addresses) { + return addresses.stream().map(member -> { + final var address = member.recipientAddress(); + return new JsonGroupMember(address.number().orElse(null), + address.uuid().map(UUID::toString).orElse(null), + member.isAdmin(), + member.labelEmoji(), + member.label()); + }).collect(Collectors.toSet()); + } + private static void printGroupPlainText(PlainTextWriter writer, Group group, boolean detailed) { if (detailed) { final var groupInviteLink = group.groupInviteLinkUrl(); writer.println( - "Id: {} Name: {} Description: {} Active: {} Blocked: {} Members: {} Pending members: {} Requesting members: {} Admins: {} Banned: {} Message expiration: {} Link: {}", + "Id: {} Name: {} Description: {} Active: {} Blocked: {} Members: {} Pending members: {} Requesting members: {} Banned: {} Message expiration: {} Link: {}", group.groupId().toBase64(), group.title(), group.description(), group.isMember(), group.isBlocked(), resolveMembers(group.members()), - resolveMembers(group.pendingMembers()), - resolveMembers(group.requestingMembers()), - resolveMembers(group.adminMembers()), - resolveMembers(group.bannedMembers()), + resolveMemberAddress(group.pendingMembers()), + resolveMemberAddress(group.requestingMembers()), + resolveMemberAddress(group.bannedMembers()), group.messageExpirationTimer() == 0 ? "disabled" : group.messageExpirationTimer() + "s", groupInviteLink == null ? '-' : groupInviteLink.getUrl()); } else { @@ -96,10 +121,14 @@ public class ListGroupsCommand implements JsonRpcLocalCommand { group.isMember(), group.isBlocked(), group.messageExpirationTimer(), - resolveJsonMembers(group.members()), + resolveFullJsonMembers(group.members()), resolveJsonMembers(group.pendingMembers()), resolveJsonMembers(group.requestingMembers()), - resolveJsonMembers(group.adminMembers()), + resolveJsonMembers(group.members() + .stream() + .filter(GroupMember::isAdmin) + .map(GroupMember::recipientAddress) + .collect(Collectors.toSet())), resolveJsonMembers(group.bannedMembers()), group.permissionAddMember().name(), group.permissionEditDetails().name(), @@ -125,15 +154,23 @@ public class ListGroupsCommand implements JsonRpcLocalCommand { boolean isBlocked, int messageExpirationTime, Set members, - Set pendingMembers, - Set requestingMembers, - Set admins, - Set banned, + Set pendingMembers, + Set requestingMembers, + @Deprecated Set admins, + Set banned, String permissionAddMember, String permissionEditDetails, String permissionSendMessage, String groupInviteLink ) {} - private record JsonGroupMember(String number, String uuid) {} + private record JsonGroupMemberAddress(String number, String uuid) {} + + private record JsonGroupMember( + String number, + String uuid, + boolean isAdmin, + @JsonInclude(JsonInclude.Include.NON_NULL) String labelEmoji, + @JsonInclude(JsonInclude.Include.NON_NULL) String label + ) {} } diff --git a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java index c0d4eb9f..70bd388b 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusManagerImpl.java @@ -12,6 +12,7 @@ import org.asamk.signal.manager.api.DeviceLinkUrl; import org.asamk.signal.manager.api.Group; import org.asamk.signal.manager.api.GroupId; import org.asamk.signal.manager.api.GroupInviteLinkUrl; +import org.asamk.signal.manager.api.GroupMember; import org.asamk.signal.manager.api.GroupNotFoundException; import org.asamk.signal.manager.api.GroupPermission; import org.asamk.signal.manager.api.GroupSendingNotAllowedException; @@ -834,24 +835,22 @@ public class DbusManagerImpl implements Manager { final var group = getRemoteObject(groupPath, Signal.Group.class).GetAll("org.asamk.Signal.Group"); final var id = (byte[]) group.get("Id").getValue(); try { + final var admins = new HashSet<>(((List) group.get("Admins").getValue())); return new Group(GroupId.unknownVersion(id), (String) group.get("Name").getValue(), (String) group.get("Description").getValue(), GroupInviteLinkUrl.fromUri((String) group.get("GroupInviteLink").getValue()), ((List) group.get("Members").getValue()).stream() - .map(m -> new RecipientAddress(m)) + .map(m -> new GroupMember(new RecipientAddress(m), admins.contains(m), null, null)) .collect(Collectors.toSet()), ((List) group.get("PendingMembers").getValue()).stream() - .map(m -> new RecipientAddress(m)) + .map(RecipientAddress::new) .collect(Collectors.toSet()), ((List) group.get("RequestingMembers").getValue()).stream() - .map(m -> new RecipientAddress(m)) - .collect(Collectors.toSet()), - ((List) group.get("Admins").getValue()).stream() - .map(m -> new RecipientAddress(m)) + .map(RecipientAddress::new) .collect(Collectors.toSet()), ((List) group.get("Banned").getValue()).stream() - .map(m -> new RecipientAddress(m)) + .map(RecipientAddress::new) .collect(Collectors.toSet()), (boolean) group.get("IsBlocked").getValue(), (int) group.get("MessageExpirationTimer").getValue(), diff --git a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java index 7a8b034a..f60cc42b 100644 --- a/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java +++ b/src/main/java/org/asamk/signal/dbus/DbusSignalImpl.java @@ -10,6 +10,7 @@ import org.asamk.signal.manager.api.DeviceLinkUrl; import org.asamk.signal.manager.api.GroupId; import org.asamk.signal.manager.api.GroupInviteLinkUrl; import org.asamk.signal.manager.api.GroupLinkState; +import org.asamk.signal.manager.api.GroupMember; import org.asamk.signal.manager.api.GroupNotFoundException; import org.asamk.signal.manager.api.GroupPermission; import org.asamk.signal.manager.api.GroupSendingNotAllowedException; @@ -624,7 +625,7 @@ public class DbusSignalImpl implements Signal, AutoCloseable { if (group == null) { return List.of(); } else { - final var members = group.members(); + final var members = group.members().stream().map(GroupMember::recipientAddress).collect(Collectors.toSet()); return getRecipientStrings(members); } } @@ -1300,13 +1301,20 @@ public class DbusSignalImpl implements Signal, AutoCloseable { () -> getGroup().messageExpirationTimer(), this::setMessageExpirationTime), new DbusProperty<>("Members", - () -> new Variant<>(getRecipientStrings(getGroup().members()), "as")), + () -> new Variant<>(getRecipientStrings(getGroup().members() + .stream() + .map(GroupMember::recipientAddress) + .collect(Collectors.toSet())), "as")), new DbusProperty<>("PendingMembers", () -> new Variant<>(getRecipientStrings(getGroup().pendingMembers()), "as")), new DbusProperty<>("RequestingMembers", () -> new Variant<>(getRecipientStrings(getGroup().requestingMembers()), "as")), new DbusProperty<>("Admins", - () -> new Variant<>(getRecipientStrings(getGroup().adminMembers()), "as")), + () -> new Variant<>(getRecipientStrings(getGroup().members() + .stream() + .filter(GroupMember::isAdmin) + .map(GroupMember::recipientAddress) + .collect(Collectors.toSet())), "as")), new DbusProperty<>("Banned", () -> new Variant<>(getRecipientStrings(getGroup().bannedMembers()), "as")), new DbusProperty<>("PermissionAddMember", diff --git a/src/main/resources/META-INF/native-image/org.asamk/signal-cli/reachability-metadata.json b/src/main/resources/META-INF/native-image/org.asamk/signal-cli/reachability-metadata.json index 8f064feb..c3108727 100644 --- a/src/main/resources/META-INF/native-image/org.asamk/signal-cli/reachability-metadata.json +++ b/src/main/resources/META-INF/native-image/org.asamk/signal-cli/reachability-metadata.json @@ -2048,6 +2048,19 @@ "allDeclaredMethods": true, "allDeclaredConstructors": true }, + { + "type": "org.asamk.signal.commands.ListGroupsCommand$JsonGroupMemberAddress", + "methods": [ + { + "name": "number", + "parameterTypes": [] + }, + { + "name": "uuid", + "parameterTypes": [] + } + ] + }, { "type": "org.asamk.signal.commands.ListIdentitiesCommand$JsonIdentity", "allDeclaredFields": true,