]> 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 1a14e8df26da631063b453fa26efac99a8ba18b4..3865d829effdf6ca757a5338b054f2d9d10a5b93 100644 (file)
 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.storage.contacts.ContactInfo;
+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.List;
+import java.util.Base64;
+import java.util.Optional;
+import java.util.UUID;
 
-public class ListContactsCommand implements LocalCommand {
+public class ListContactsCommand implements JsonRpcLocalCommand {
+
+    @Override
+    public String getName() {
+        return "listContacts";
+    }
 
     @Override
     public void attachToSubparser(final Subparser subparser) {
+        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 int handleCommand(final Namespace ns, final Manager m) {
-        List<ContactInfo> contacts = m.getContacts();
-        for (ContactInfo c : contacts) {
-            System.out.println(String.format("Number: %s Name: %s  Blocked: %b", c.number, c.name, c.blocked));
+    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);
+            }
         }
-        return 0;
     }
 }