import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
-import org.asamk.signal.JsonWriter;
-import org.asamk.signal.OutputType;
+import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.manager.Manager;
-import org.asamk.signal.manager.storage.groups.GroupInfo;
+import org.asamk.signal.manager.api.Group;
+import org.asamk.signal.manager.api.RecipientAddress;
+import org.asamk.signal.output.JsonWriter;
+import org.asamk.signal.output.OutputWriter;
+import org.asamk.signal.output.PlainTextWriter;
+import org.asamk.signal.util.CommandUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.whispersystems.signalservice.api.push.SignalServiceAddress;
-import java.io.IOException;
-import java.util.ArrayList;
import java.util.Set;
+import java.util.UUID;
import java.util.stream.Collectors;
-public class ListGroupsCommand implements LocalCommand {
+public class ListGroupsCommand implements JsonRpcLocalCommand {
- private final static Logger logger = LoggerFactory.getLogger(ListGroupsCommand.class);
+ private static final Logger logger = LoggerFactory.getLogger(ListGroupsCommand.class);
- private static Set<String> resolveMembers(Manager m, Set<SignalServiceAddress> addresses) {
- return addresses.stream()
- .map(m::resolveSignalServiceAddress)
- .map(SignalServiceAddress::getLegacyIdentifier)
- .collect(Collectors.toSet());
- }
-
- private static void printGroupPlainText(Manager m, GroupInfo group, boolean detailed) {
- if (detailed) {
- final var groupInviteLink = group.getGroupInviteLink();
-
- System.out.println(String.format(
- "Id: %s Name: %s Active: %s Blocked: %b Members: %s Pending members: %s Requesting members: %s Link: %s",
- group.getGroupId().toBase64(),
- group.getTitle(),
- group.isMember(m.getSelfAddress()),
- group.isBlocked(),
- resolveMembers(m, group.getMembers()),
- resolveMembers(m, group.getPendingMembers()),
- resolveMembers(m, group.getRequestingMembers()),
- groupInviteLink == null ? '-' : groupInviteLink.getUrl()));
- } else {
- System.out.println(String.format("Id: %s Name: %s Active: %s Blocked: %b",
- group.getGroupId().toBase64(),
- group.getTitle(),
- group.isMember(m.getSelfAddress()),
- group.isBlocked()));
- }
+ @Override
+ public String getName() {
+ return "listGroups";
}
@Override
public void attachToSubparser(final Subparser subparser) {
+ subparser.help("List group information including names, ids, active status, blocked status and members");
subparser.addArgument("-d", "--detailed")
.action(Arguments.storeTrue())
.help("List the members and group invite links of each group. If output=json, then this is always set");
+ subparser.addArgument("-g", "--group-id").help("Specify one or more group IDs to show.").nargs("*");
+ }
- subparser.help("List group information including names, ids, active status, blocked status and members");
+ private static Set<String> resolveMembers(Set<RecipientAddress> addresses) {
+ return addresses.stream().map(RecipientAddress::getLegacyIdentifier).collect(Collectors.toSet());
}
- @Override
- public Set<OutputType> getSupportedOutputTypes() {
- return Set.of(OutputType.PLAIN_TEXT, OutputType.JSON);
+ private static Set<JsonGroupMember> resolveJsonMembers(Set<RecipientAddress> addresses) {
+ return addresses.stream()
+ .map(address -> new JsonGroupMember(address.number().orElse(null),
+ address.uuid().map(UUID::toString).orElse(null)))
+ .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: {}",
+ 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()),
+ group.messageExpirationTimer() == 0 ? "disabled" : group.messageExpirationTimer() + "s",
+ groupInviteLink == null ? '-' : groupInviteLink.getUrl());
+ } else {
+ writer.println("Id: {} Name: {} Active: {} Blocked: {}",
+ group.groupId().toBase64(),
+ group.title(),
+ group.isMember(),
+ group.isBlocked());
+ }
}
@Override
- public int handleCommand(final Namespace ns, final Manager m) {
- if (ns.get("output") == OutputType.JSON) {
- final var jsonWriter = new JsonWriter(System.out);
-
- var jsonGroups = new ArrayList<JsonGroup>();
- for (var group : m.getGroups()) {
- final var groupInviteLink = group.getGroupInviteLink();
-
- jsonGroups.add(new JsonGroup(group.getGroupId().toBase64(),
- group.getTitle(),
- group.isMember(m.getSelfAddress()),
- group.isBlocked(),
- resolveMembers(m, group.getMembers()),
- resolveMembers(m, group.getPendingMembers()),
- resolveMembers(m, group.getRequestingMembers()),
- groupInviteLink == null ? null : groupInviteLink.getUrl()));
- }
+ public void handleCommand(
+ final Namespace ns,
+ final Manager m,
+ final OutputWriter outputWriter
+ ) throws CommandException {
+ var groups = m.getGroups();
+
+ final var groupIdStrings = ns.<String>getList("group-id");
+ final var groupIds = CommandUtil.getGroupIds(groupIdStrings);
+ if (!groupIds.isEmpty()) {
+ groups = groups.stream().filter(g -> groupIds.contains(g.groupId())).toList();
+ }
- try {
+ switch (outputWriter) {
+ case JsonWriter jsonWriter -> {
+ var jsonGroups = groups.stream().map(group -> {
+ final var groupInviteLink = group.groupInviteLinkUrl();
+
+ return new JsonGroup(group.groupId().toBase64(),
+ group.title(),
+ group.description(),
+ group.isMember(),
+ group.isBlocked(),
+ group.messageExpirationTimer(),
+ resolveJsonMembers(group.members()),
+ resolveJsonMembers(group.pendingMembers()),
+ resolveJsonMembers(group.requestingMembers()),
+ resolveJsonMembers(group.adminMembers()),
+ resolveJsonMembers(group.bannedMembers()),
+ group.permissionAddMember().name(),
+ group.permissionEditDetails().name(),
+ group.permissionSendMessage().name(),
+ groupInviteLink == null ? null : groupInviteLink.getUrl());
+ }).toList();
jsonWriter.write(jsonGroups);
- } catch (IOException e) {
- logger.error("Failed to write json object: {}", e.getMessage());
- return 3;
}
-
- return 0;
- } else {
- boolean detailed = ns.getBoolean("detailed");
- for (var group : m.getGroups()) {
- printGroupPlainText(m, group, detailed);
+ case PlainTextWriter writer -> {
+ boolean detailed = Boolean.TRUE.equals(ns.getBoolean("detailed"));
+ for (var group : groups) {
+ printGroupPlainText(writer, group, detailed);
+ }
}
}
-
- return 0;
}
- private static final class JsonGroup {
-
- public String id;
- public String name;
- public boolean isMember;
- public boolean isBlocked;
-
- public Set<String> members;
- public Set<String> pendingMembers;
- public Set<String> requestingMembers;
- public String groupInviteLink;
-
- public JsonGroup(
- String id,
- String name,
- boolean isMember,
- boolean isBlocked,
- Set<String> members,
- Set<String> pendingMembers,
- Set<String> requestingMembers,
- String groupInviteLink
- ) {
- this.id = id;
- this.name = name;
- this.isMember = isMember;
- this.isBlocked = isBlocked;
-
- this.members = members;
- this.pendingMembers = pendingMembers;
- this.requestingMembers = requestingMembers;
- this.groupInviteLink = groupInviteLink;
- }
- }
+ private record JsonGroup(
+ String id,
+ String name,
+ String description,
+ boolean isMember,
+ boolean isBlocked,
+ int messageExpirationTime,
+ Set<JsonGroupMember> members,
+ Set<JsonGroupMember> pendingMembers,
+ Set<JsonGroupMember> requestingMembers,
+ Set<JsonGroupMember> admins,
+ Set<JsonGroupMember> banned,
+ String permissionAddMember,
+ String permissionEditDetails,
+ String permissionSendMessage,
+ String groupInviteLink
+ ) {}
+
+ private record JsonGroupMember(String number, String uuid) {}
}