]> nmode's Git Repositories - signal-cli/blob - src/main/java/org/asamk/signal/commands/ListContactsCommand.java
Extend updateContact command with nick given/family name and note
[signal-cli] / src / main / java / org / asamk / signal / commands / ListContactsCommand.java
1 package org.asamk.signal.commands;
2
3 import net.sourceforge.argparse4j.impl.Arguments;
4 import net.sourceforge.argparse4j.inf.Namespace;
5 import net.sourceforge.argparse4j.inf.Subparser;
6
7 import org.asamk.signal.commands.exceptions.CommandException;
8 import org.asamk.signal.json.JsonContact;
9 import org.asamk.signal.manager.Manager;
10 import org.asamk.signal.manager.api.Contact;
11 import org.asamk.signal.manager.api.PhoneNumberSharingMode;
12 import org.asamk.signal.manager.api.Profile;
13 import org.asamk.signal.output.JsonWriter;
14 import org.asamk.signal.output.OutputWriter;
15 import org.asamk.signal.output.PlainTextWriter;
16 import org.asamk.signal.util.CommandUtil;
17
18 import java.util.Base64;
19 import java.util.Optional;
20 import java.util.UUID;
21
22 public class ListContactsCommand implements JsonRpcLocalCommand {
23
24 @Override
25 public String getName() {
26 return "listContacts";
27 }
28
29 @Override
30 public void attachToSubparser(final Subparser subparser) {
31 subparser.help("Show a list of known contacts with names and profiles.");
32 subparser.addArgument("recipient").help("Specify one ore more phone numbers to show.").nargs("*");
33 subparser.addArgument("-a", "--all-recipients")
34 .action(Arguments.storeTrue())
35 .help("Include all known recipients, not only contacts.");
36 subparser.addArgument("--blocked")
37 .type(Boolean.class)
38 .help("Specify if only blocked or unblocked contacts should be shown (default: all contacts)");
39 subparser.addArgument("--name").help("Find contacts with the given contact or profile name.");
40 subparser.addArgument("--detailed")
41 .action(Arguments.storeTrue())
42 .help("List the contacts with more details. If output=json, then this is always set");
43 subparser.addArgument("--internal")
44 .action(Arguments.storeTrue())
45 .help("Include internal information that's normally not user visible");
46 }
47
48 @Override
49 public void handleCommand(
50 final Namespace ns,
51 final Manager m,
52 final OutputWriter outputWriter
53 ) throws CommandException {
54 final var allRecipients = Boolean.TRUE.equals(ns.getBoolean("all-recipients"));
55 final var blocked = ns.getBoolean("blocked");
56 final var recipientStrings = ns.<String>getList("recipient");
57 final var recipientIdentifiers = CommandUtil.getSingleRecipientIdentifiers(recipientStrings, m.getSelfNumber());
58 final var name = ns.getString("name");
59 final var recipients = m.getRecipients(!allRecipients,
60 Optional.ofNullable(blocked),
61 recipientIdentifiers,
62 Optional.ofNullable(name));
63
64 final var detailed = Boolean.TRUE.equals(ns.getBoolean("detailed"));
65 final var internal = Boolean.TRUE.equals(ns.getBoolean("internal"));
66
67 switch (outputWriter) {
68 case PlainTextWriter writer -> {
69 for (var r : recipients) {
70 final var contact = r.getContact() == null ? Contact.newBuilder().build() : r.getContact();
71 final var profile = r.getProfile() == null ? Profile.newBuilder().build() : r.getProfile();
72 writer.println(
73 "Number: {} ACI: {} Name: {} Profile name: {} Username: {} Color: {} Blocked: {} Message expiration: {}",
74 r.getAddress().number().orElse(""),
75 r.getAddress().aci().orElse(""),
76 contact.getName(),
77 profile.getDisplayName(),
78 r.getAddress().username().orElse(""),
79 Optional.ofNullable(contact.color()).orElse(""),
80 contact.isBlocked(),
81 contact.messageExpirationTime() == 0 ? "disabled" : contact.messageExpirationTime() + "s");
82 if (detailed) {
83 writer.indentedWriter()
84 .println(
85 "PNI: {} Given name: {} Family name: {}, Nick name: {} Nick given name: {} Nick family name {} Note: {} Archived: {} Hidden: {} Profile sharing: {} About: {} About Emoji: {} Unregistered: {}",
86 r.getAddress().pni().orElse(""),
87 Optional.ofNullable(r.getContact().givenName()).orElse(""),
88 Optional.ofNullable(r.getContact().familyName()).orElse(""),
89 Optional.ofNullable(r.getContact().nickName()).orElse(""),
90 Optional.ofNullable(r.getContact().nickNameGivenName()).orElse(""),
91 Optional.ofNullable(r.getContact().nickNameFamilyName()).orElse(""),
92 Optional.ofNullable(r.getContact().note()).orElse(""),
93 r.getContact().isArchived(),
94 r.getContact().isHidden(),
95 r.getContact().isProfileSharingEnabled(),
96 Optional.ofNullable(r.getProfile().getAbout()).orElse(""),
97 Optional.ofNullable(r.getProfile().getAboutEmoji()).orElse(""),
98 r.getContact().unregisteredTimestamp() != null);
99 }
100 if (internal) {
101 writer.indentedWriter()
102 .println(
103 "Capabilities: {} Unidentified access mode: {} Shares number: {} Discoverable by number: {}",
104 r.getProfile().getCapabilities().stream().map(Enum::name).toList(),
105 Optional.ofNullable(r.getProfile().getUnidentifiedAccessMode()
106 == Profile.UnidentifiedAccessMode.UNKNOWN
107 ? null
108 : r.getProfile().getUnidentifiedAccessMode().name()).orElse(""),
109 r.getProfile().getPhoneNumberSharingMode() == null
110 ? ""
111 : String.valueOf(r.getProfile().getPhoneNumberSharingMode()
112 == PhoneNumberSharingMode.EVERYBODY),
113 r.getDiscoverable() == null ? "" : String.valueOf(r.getDiscoverable()));
114 }
115 }
116 }
117 case JsonWriter writer -> {
118 final var jsonContacts = recipients.stream().map(r -> {
119 final var address = r.getAddress();
120 final var contact = r.getContact() == null ? Contact.newBuilder().build() : r.getContact();
121 final var jsonInternal = !internal
122 ? null
123 : new JsonContact.JsonInternal(r.getProfile()
124 .getCapabilities()
125 .stream()
126 .map(Enum::name)
127 .toList(),
128 r.getProfile().getUnidentifiedAccessMode() == Profile.UnidentifiedAccessMode.UNKNOWN
129 ? null
130 : r.getProfile().getUnidentifiedAccessMode().name(),
131 r.getProfile().getPhoneNumberSharingMode() == null
132 ? null
133 : r.getProfile().getPhoneNumberSharingMode()
134 == PhoneNumberSharingMode.EVERYBODY,
135 r.getDiscoverable());
136 return new JsonContact(address.number().orElse(null),
137 address.uuid().map(UUID::toString).orElse(null),
138 address.username().orElse(null),
139 contact.getName(),
140 contact.givenName(),
141 contact.familyName(),
142 contact.nickName(),
143 contact.nickNameGivenName(),
144 contact.nickNameFamilyName(),
145 contact.note(),
146 contact.color(),
147 contact.isBlocked(),
148 contact.isHidden(),
149 contact.messageExpirationTime(),
150 r.getContact().isProfileSharingEnabled(),
151 r.getContact().unregisteredTimestamp() != null,
152 r.getProfile() == null
153 ? null
154 : new JsonContact.JsonProfile(r.getProfile().getLastUpdateTimestamp(),
155 r.getProfile().getGivenName(),
156 r.getProfile().getFamilyName(),
157 r.getProfile().getAbout(),
158 r.getProfile().getAboutEmoji(),
159 r.getProfile().getAvatarUrlPath() != null,
160 r.getProfile().getMobileCoinAddress() == null
161 ? null
162 : Base64.getEncoder()
163 .encodeToString(r.getProfile().getMobileCoinAddress())),
164 jsonInternal);
165 }).toList();
166 writer.write(jsonContacts);
167 }
168 }
169 }
170 }