mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 18:40:39 +00:00
Implement remove group members
This commit is contained in:
parent
4ebacd0e1f
commit
a91e3f762e
4 changed files with 77 additions and 6 deletions
|
@ -826,22 +826,33 @@ public class Manager implements Closeable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pair<Long, List<SendMessageResult>> updateGroup(
|
public Pair<Long, List<SendMessageResult>> updateGroup(
|
||||||
GroupId groupId, String name, String description, List<String> members, File avatarFile
|
GroupId groupId,
|
||||||
|
String name,
|
||||||
|
String description,
|
||||||
|
List<String> members,
|
||||||
|
List<String> removeMembers,
|
||||||
|
File avatarFile
|
||||||
) throws IOException, GroupNotFoundException, AttachmentInvalidException, InvalidNumberException, NotAGroupMemberException {
|
) throws IOException, GroupNotFoundException, AttachmentInvalidException, InvalidNumberException, NotAGroupMemberException {
|
||||||
return updateGroup(groupId,
|
return updateGroup(groupId,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
members == null ? null : getSignalServiceAddresses(members),
|
members == null ? null : getSignalServiceAddresses(members),
|
||||||
|
removeMembers == null ? null : getSignalServiceAddresses(removeMembers),
|
||||||
avatarFile);
|
avatarFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<Long, List<SendMessageResult>> updateGroup(
|
private Pair<Long, List<SendMessageResult>> updateGroup(
|
||||||
GroupId groupId, String name, String description, Set<RecipientId> members, File avatarFile
|
GroupId groupId,
|
||||||
|
String name,
|
||||||
|
String description,
|
||||||
|
Set<RecipientId> members,
|
||||||
|
final Set<RecipientId> removeMembers,
|
||||||
|
File avatarFile
|
||||||
) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException {
|
) throws IOException, GroupNotFoundException, AttachmentInvalidException, NotAGroupMemberException {
|
||||||
var group = getGroupForUpdating(groupId);
|
var group = getGroupForUpdating(groupId);
|
||||||
|
|
||||||
if (group instanceof GroupInfoV2) {
|
if (group instanceof GroupInfoV2) {
|
||||||
return updateGroupV2((GroupInfoV2) group, name, description, members, avatarFile);
|
return updateGroupV2((GroupInfoV2) group, name, description, members, removeMembers, avatarFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
return updateGroupV1((GroupInfoV1) group, name, members, avatarFile);
|
return updateGroupV1((GroupInfoV1) group, name, members, avatarFile);
|
||||||
|
@ -901,6 +912,7 @@ public class Manager implements Closeable {
|
||||||
final String name,
|
final String name,
|
||||||
final String description,
|
final String description,
|
||||||
final Set<RecipientId> members,
|
final Set<RecipientId> members,
|
||||||
|
final Set<RecipientId> removeMembers,
|
||||||
final File avatarFile
|
final File avatarFile
|
||||||
) throws IOException {
|
) throws IOException {
|
||||||
Pair<Long, List<SendMessageResult>> result = null;
|
Pair<Long, List<SendMessageResult>> result = null;
|
||||||
|
@ -917,6 +929,24 @@ public class Manager implements Closeable {
|
||||||
result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second());
|
result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (removeMembers != null) {
|
||||||
|
var existingRemoveMembers = new HashSet<>(removeMembers);
|
||||||
|
existingRemoveMembers.retainAll(group.getMembers());
|
||||||
|
existingRemoveMembers.remove(getSelfRecipientId());// self can be removed with sendQuitGroupMessage
|
||||||
|
if (existingRemoveMembers.size() > 0) {
|
||||||
|
var groupGroupChangePair = groupHelper.removeMembers(group, existingRemoveMembers);
|
||||||
|
result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second());
|
||||||
|
}
|
||||||
|
|
||||||
|
var pendingRemoveMembers = new HashSet<>(removeMembers);
|
||||||
|
pendingRemoveMembers.retainAll(group.getPendingMembers());
|
||||||
|
if (pendingRemoveMembers.size() > 0) {
|
||||||
|
var groupGroupChangePair = groupHelper.revokeInvitedMembers(group, pendingRemoveMembers);
|
||||||
|
result = sendUpdateGroupV2Message(group, groupGroupChangePair.first(), groupGroupChangePair.second());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (result == null || name != null || description != null || avatarFile != null) {
|
if (result == null || name != null || description != null || avatarFile != null) {
|
||||||
var groupGroupChangePair = groupHelper.updateGroupV2(group, name, description, avatarFile);
|
var groupGroupChangePair = groupHelper.updateGroupV2(group, name, description, avatarFile);
|
||||||
if (avatarFile != null) {
|
if (avatarFile != null) {
|
||||||
|
@ -954,10 +984,14 @@ public class Manager implements Closeable {
|
||||||
private Pair<Long, List<SendMessageResult>> sendUpdateGroupV2Message(
|
private Pair<Long, List<SendMessageResult>> sendUpdateGroupV2Message(
|
||||||
GroupInfoV2 group, DecryptedGroup newDecryptedGroup, GroupChange groupChange
|
GroupInfoV2 group, DecryptedGroup newDecryptedGroup, GroupChange groupChange
|
||||||
) throws IOException {
|
) throws IOException {
|
||||||
|
final var selfRecipientId = account.getSelfRecipientId();
|
||||||
|
final var members = group.getMembersIncludingPendingWithout(selfRecipientId);
|
||||||
group.setGroup(newDecryptedGroup, this::resolveRecipient);
|
group.setGroup(newDecryptedGroup, this::resolveRecipient);
|
||||||
|
members.addAll(group.getMembersIncludingPendingWithout(selfRecipientId));
|
||||||
|
|
||||||
final var messageBuilder = getGroupUpdateMessageBuilder(group, groupChange.toByteArray());
|
final var messageBuilder = getGroupUpdateMessageBuilder(group, groupChange.toByteArray());
|
||||||
account.getGroupStore().updateGroup(group);
|
account.getGroupStore().updateGroup(group);
|
||||||
return sendMessage(messageBuilder, group.getMembersIncludingPendingWithout(account.getSelfRecipientId()));
|
return sendMessage(messageBuilder, members);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int currentTimeDays() {
|
private static int currentTimeDays() {
|
||||||
|
|
|
@ -263,6 +263,34 @@ public class GroupHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Pair<DecryptedGroup, GroupChange> removeMembers(
|
||||||
|
GroupInfoV2 groupInfoV2, Set<RecipientId> members
|
||||||
|
) throws IOException {
|
||||||
|
final var memberUuids = members.stream()
|
||||||
|
.map(addressResolver::resolveSignalServiceAddress)
|
||||||
|
.map(SignalServiceAddress::getUuid)
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
return ejectMembers(groupInfoV2, memberUuids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pair<DecryptedGroup, GroupChange> revokeInvitedMembers(
|
||||||
|
GroupInfoV2 groupInfoV2, Set<RecipientId> members
|
||||||
|
) throws IOException {
|
||||||
|
var pendingMembersList = groupInfoV2.getGroup().getPendingMembersList();
|
||||||
|
final var memberUuids = members.stream()
|
||||||
|
.map(addressResolver::resolveSignalServiceAddress)
|
||||||
|
.map(SignalServiceAddress::getUuid)
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.map(uuid -> DecryptedGroupUtil.findPendingByUuid(pendingMembersList, uuid))
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
return revokeInvites(groupInfoV2, memberUuids);
|
||||||
|
}
|
||||||
|
|
||||||
public GroupChange joinGroup(
|
public GroupChange joinGroup(
|
||||||
GroupMasterKey groupMasterKey,
|
GroupMasterKey groupMasterKey,
|
||||||
GroupLinkPassword groupLinkPassword,
|
GroupLinkPassword groupLinkPassword,
|
||||||
|
@ -309,7 +337,7 @@ public class GroupHelper {
|
||||||
return commitChange(groupInfoV2, change);
|
return commitChange(groupInfoV2, change);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pair<DecryptedGroup, GroupChange> revokeInvites(
|
private Pair<DecryptedGroup, GroupChange> revokeInvites(
|
||||||
GroupInfoV2 groupInfoV2, Set<DecryptedPendingMember> pendingMembers
|
GroupInfoV2 groupInfoV2, Set<DecryptedPendingMember> pendingMembers
|
||||||
) throws IOException {
|
) throws IOException {
|
||||||
final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
|
final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
|
||||||
|
@ -324,7 +352,9 @@ public class GroupHelper {
|
||||||
return commitChange(groupInfoV2, groupOperations.createRemoveInvitationChange(uuidCipherTexts));
|
return commitChange(groupInfoV2, groupOperations.createRemoveInvitationChange(uuidCipherTexts));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pair<DecryptedGroup, GroupChange> ejectMembers(GroupInfoV2 groupInfoV2, Set<UUID> uuids) throws IOException {
|
private Pair<DecryptedGroup, GroupChange> ejectMembers(
|
||||||
|
GroupInfoV2 groupInfoV2, Set<UUID> uuids
|
||||||
|
) throws IOException {
|
||||||
final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
|
final var groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupInfoV2.getMasterKey());
|
||||||
final var groupOperations = groupsV2Operations.forGroup(groupSecretParams);
|
final var groupOperations = groupsV2Operations.forGroup(groupSecretParams);
|
||||||
return commitChange(groupInfoV2, groupOperations.createRemoveMembersChange(uuids));
|
return commitChange(groupInfoV2, groupOperations.createRemoveMembersChange(uuids));
|
||||||
|
|
|
@ -38,6 +38,9 @@ public class UpdateGroupCommand implements DbusCommand, LocalCommand {
|
||||||
subparser.addArgument("-d", "--description").help("Specify the new group description.");
|
subparser.addArgument("-d", "--description").help("Specify the new group description.");
|
||||||
subparser.addArgument("-a", "--avatar").help("Specify a new group avatar image file");
|
subparser.addArgument("-a", "--avatar").help("Specify a new group avatar image file");
|
||||||
subparser.addArgument("-m", "--member").nargs("*").help("Specify one or more members to add to the group");
|
subparser.addArgument("-m", "--member").nargs("*").help("Specify one or more members to add to the group");
|
||||||
|
subparser.addArgument("-r", "--remove-member")
|
||||||
|
.nargs("*")
|
||||||
|
.help("Specify one or more members to remove from the group");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -59,6 +62,8 @@ public class UpdateGroupCommand implements DbusCommand, LocalCommand {
|
||||||
|
|
||||||
List<String> groupMembers = ns.getList("member");
|
List<String> groupMembers = ns.getList("member");
|
||||||
|
|
||||||
|
List<String> groupRemoveMembers = ns.getList("remove-member");
|
||||||
|
|
||||||
var groupAvatar = ns.getString("avatar");
|
var groupAvatar = ns.getString("avatar");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -74,6 +79,7 @@ public class UpdateGroupCommand implements DbusCommand, LocalCommand {
|
||||||
groupName,
|
groupName,
|
||||||
groupDescription,
|
groupDescription,
|
||||||
groupMembers,
|
groupMembers,
|
||||||
|
groupRemoveMembers,
|
||||||
groupAvatar == null ? null : new File(groupAvatar));
|
groupAvatar == null ? null : new File(groupAvatar));
|
||||||
ErrorUtils.handleTimestampAndSendMessageResults(writer, results.first(), results.second());
|
ErrorUtils.handleTimestampAndSendMessageResults(writer, results.first(), results.second());
|
||||||
}
|
}
|
||||||
|
|
|
@ -344,6 +344,7 @@ public class DbusSignalImpl implements Signal {
|
||||||
name,
|
name,
|
||||||
null,
|
null,
|
||||||
members,
|
members,
|
||||||
|
null,
|
||||||
avatar == null ? null : new File(avatar));
|
avatar == null ? null : new File(avatar));
|
||||||
checkSendMessageResults(results.first(), results.second());
|
checkSendMessageResults(results.first(), results.second());
|
||||||
return groupId;
|
return groupId;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue