]> nmode's Git Repositories - signal-cli/blobdiff - src/main/java/org/asamk/signal/commands/ListContactsCommand.java
Add more details to listContacts command
[signal-cli] / src / main / java / org / asamk / signal / commands / ListContactsCommand.java
index 308044dc2f2783be7b3b4b3ebe621846e5c37c55..3865d829effdf6ca757a5338b054f2d9d10a5b93 100644 (file)
@@ -1,15 +1,23 @@
 package org.asamk.signal.commands;
 
+import net.sourceforge.argparse4j.impl.Arguments;
 import net.sourceforge.argparse4j.inf.Namespace;
 import net.sourceforge.argparse4j.inf.Subparser;
 
+import org.asamk.signal.commands.exceptions.CommandException;
+import org.asamk.signal.json.JsonContact;
 import org.asamk.signal.manager.Manager;
+import org.asamk.signal.manager.api.Contact;
+import org.asamk.signal.manager.api.PhoneNumberSharingMode;
+import org.asamk.signal.manager.api.Profile;
 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 java.util.Base64;
+import java.util.Optional;
 import java.util.UUID;
-import java.util.stream.Collectors;
 
 public class ListContactsCommand implements JsonRpcLocalCommand {
 
@@ -20,39 +28,141 @@ public class ListContactsCommand implements JsonRpcLocalCommand {
 
     @Override
     public void attachToSubparser(final Subparser subparser) {
-        subparser.help("Show a list of known contacts with names.");
+        subparser.help("Show a list of known contacts with names and profiles.");
+        subparser.addArgument("recipient").help("Specify one ore more phone numbers to show.").nargs("*");
+        subparser.addArgument("-a", "--all-recipients")
+                .action(Arguments.storeTrue())
+                .help("Include all known recipients, not only contacts.");
+        subparser.addArgument("--blocked")
+                .type(Boolean.class)
+                .help("Specify if only blocked or unblocked contacts should be shown (default: all contacts)");
+        subparser.addArgument("--name").help("Find contacts with the given contact or profile name.");
+        subparser.addArgument("--detailed")
+                .action(Arguments.storeTrue())
+                .help("List the contacts with more details. If output=json, then this is always set");
+        subparser.addArgument("--internal")
+                .action(Arguments.storeTrue())
+                .help("Include internal information that's normally not user visible");
     }
 
     @Override
-    public void handleCommand(final Namespace ns, final Manager m, final OutputWriter outputWriter) {
-        var contacts = m.getContacts();
-
-        if (outputWriter instanceof PlainTextWriter writer) {
-            for (var c : contacts) {
-                final var contact = c.second();
-                writer.println("Number: {} Name: {} Blocked: {} Message expiration: {}",
-                        c.first().getLegacyIdentifier(),
-                        contact.getName(),
-                        contact.isBlocked(),
-                        contact.getMessageExpirationTime() == 0
-                                ? "disabled"
-                                : contact.getMessageExpirationTime() + "s");
+    public void handleCommand(
+            final Namespace ns, final Manager m, final OutputWriter outputWriter
+    ) throws CommandException {
+        final var allRecipients = Boolean.TRUE.equals(ns.getBoolean("all-recipients"));
+        final var blocked = ns.getBoolean("blocked");
+        final var recipientStrings = ns.<String>getList("recipient");
+        final var recipientIdentifiers = CommandUtil.getSingleRecipientIdentifiers(recipientStrings, m.getSelfNumber());
+        final var name = ns.getString("name");
+        final var recipients = m.getRecipients(!allRecipients,
+                Optional.ofNullable(blocked),
+                recipientIdentifiers,
+                Optional.ofNullable(name));
+
+        final var detailed = Boolean.TRUE.equals(ns.getBoolean("detailed"));
+        final var internal = Boolean.TRUE.equals(ns.getBoolean("internal"));
+
+        switch (outputWriter) {
+            case PlainTextWriter writer -> {
+                for (var r : recipients) {
+                    final var contact = r.getContact() == null ? Contact.newBuilder().build() : r.getContact();
+                    final var profile = r.getProfile() == null ? Profile.newBuilder().build() : r.getProfile();
+                    writer.println(
+                            "Number: {} ACI: {} Name: {} Profile name: {} Username: {} Color: {} Blocked: {} Message expiration: {}",
+                            r.getAddress().number().orElse(""),
+                            r.getAddress().aci().orElse(""),
+                            contact.getName(),
+                            profile.getDisplayName(),
+                            r.getAddress().username().orElse(""),
+                            Optional.ofNullable(contact.color()).orElse(""),
+                            contact.isBlocked(),
+                            contact.messageExpirationTime() == 0 ? "disabled" : contact.messageExpirationTime() + "s");
+                    if (detailed) {
+                        writer.indentedWriter()
+                                .println(
+                                        "PNI: {} Given name: {} Family name: {}, Nick name: {} Nick given name: {} Nick family name {} Note: {} Archived: {} Hidden: {} Profile sharing: {} About: {} About Emoji: {} Unregistered: {}",
+                                        r.getAddress().pni().orElse(""),
+                                        Optional.ofNullable(r.getContact().givenName()).orElse(""),
+                                        Optional.ofNullable(r.getContact().familyName()).orElse(""),
+                                        Optional.ofNullable(r.getContact().nickName()).orElse(""),
+                                        Optional.ofNullable(r.getContact().nickNameGivenName()).orElse(""),
+                                        Optional.ofNullable(r.getContact().nickNameFamilyName()).orElse(""),
+                                        Optional.ofNullable(r.getContact().note()).orElse(""),
+                                        r.getContact().isArchived(),
+                                        r.getContact().isHidden(),
+                                        r.getContact().isProfileSharingEnabled(),
+                                        Optional.ofNullable(r.getProfile().getAbout()).orElse(""),
+                                        Optional.ofNullable(r.getProfile().getAboutEmoji()).orElse(""),
+                                        r.getContact().unregisteredTimestamp() != null);
+                    }
+                    if (internal) {
+                        writer.indentedWriter()
+                                .println(
+                                        "Capabilities: {} Unidentified access mode: {} Shares number: {} Discoverable by number: {}",
+                                        r.getProfile().getCapabilities().stream().map(Enum::name).toList(),
+                                        Optional.ofNullable(r.getProfile().getUnidentifiedAccessMode()
+                                                == Profile.UnidentifiedAccessMode.UNKNOWN
+                                                ? null
+                                                : r.getProfile().getUnidentifiedAccessMode().name()).orElse(""),
+                                        r.getProfile().getPhoneNumberSharingMode() == null
+                                                ? ""
+                                                : String.valueOf(r.getProfile().getPhoneNumberSharingMode()
+                                                        == PhoneNumberSharingMode.EVERYBODY),
+                                        r.getDiscoverable() == null ? "" : String.valueOf(r.getDiscoverable()));
+                    }
+                }
+            }
+            case JsonWriter writer -> {
+                final var jsonContacts = recipients.stream().map(r -> {
+                    final var address = r.getAddress();
+                    final var contact = r.getContact() == null ? Contact.newBuilder().build() : r.getContact();
+                    final var jsonInternal = !internal
+                            ? null
+                            : new JsonContact.JsonInternal(r.getProfile()
+                                    .getCapabilities()
+                                    .stream()
+                                    .map(Enum::name)
+                                    .toList(),
+                                    r.getProfile().getUnidentifiedAccessMode() == Profile.UnidentifiedAccessMode.UNKNOWN
+                                            ? null
+                                            : r.getProfile().getUnidentifiedAccessMode().name(),
+                                    r.getProfile().getPhoneNumberSharingMode() == null
+                                            ? null
+                                            : r.getProfile().getPhoneNumberSharingMode()
+                                                    == PhoneNumberSharingMode.EVERYBODY,
+                                    r.getDiscoverable());
+                    return new JsonContact(address.number().orElse(null),
+                            address.uuid().map(UUID::toString).orElse(null),
+                            address.username().orElse(null),
+                            contact.getName(),
+                            contact.givenName(),
+                            contact.familyName(),
+                            contact.nickName(),
+                            contact.nickNameGivenName(),
+                            contact.nickNameFamilyName(),
+                            contact.note(),
+                            contact.color(),
+                            contact.isBlocked(),
+                            contact.isHidden(),
+                            contact.messageExpirationTime(),
+                            r.getContact().isProfileSharingEnabled(),
+                            r.getContact().unregisteredTimestamp() != null,
+                            r.getProfile() == null
+                                    ? null
+                                    : new JsonContact.JsonProfile(r.getProfile().getLastUpdateTimestamp(),
+                                            r.getProfile().getGivenName(),
+                                            r.getProfile().getFamilyName(),
+                                            r.getProfile().getAbout(),
+                                            r.getProfile().getAboutEmoji(),
+                                            r.getProfile().getAvatarUrlPath() != null,
+                                            r.getProfile().getMobileCoinAddress() == null
+                                                    ? null
+                                                    : Base64.getEncoder()
+                                                            .encodeToString(r.getProfile().getMobileCoinAddress())),
+                            jsonInternal);
+                }).toList();
+                writer.write(jsonContacts);
             }
-        } else {
-            final var writer = (JsonWriter) outputWriter;
-            final var jsonContacts = contacts.stream().map(contactPair -> {
-                final var address = contactPair.first();
-                final var contact = contactPair.second();
-                return new JsonContact(address.number().orElse(null),
-                        address.uuid().map(UUID::toString).orElse(null),
-                        contact.getName(),
-                        contact.isBlocked(),
-                        contact.getMessageExpirationTime());
-            }).collect(Collectors.toList());
-
-            writer.write(jsonContacts);
         }
     }
-
-    private record JsonContact(String number, String uuid, String name, boolean isBlocked, int messageExpirationTime) {}
 }