1 package org
.asamk
.signal
.commands
;
3 import net
.sourceforge
.argparse4j
.impl
.Arguments
;
4 import net
.sourceforge
.argparse4j
.inf
.Namespace
;
5 import net
.sourceforge
.argparse4j
.inf
.Subparser
;
7 import org
.asamk
.signal
.commands
.exceptions
.CommandException
;
8 import org
.asamk
.signal
.manager
.Manager
;
9 import org
.asamk
.signal
.manager
.api
.Contact
;
10 import org
.asamk
.signal
.manager
.api
.Profile
;
11 import org
.asamk
.signal
.output
.JsonWriter
;
12 import org
.asamk
.signal
.output
.OutputWriter
;
13 import org
.asamk
.signal
.output
.PlainTextWriter
;
14 import org
.asamk
.signal
.util
.CommandUtil
;
16 import java
.util
.Base64
;
17 import java
.util
.Optional
;
18 import java
.util
.UUID
;
20 public class ListContactsCommand
implements JsonRpcLocalCommand
{
23 public String
getName() {
24 return "listContacts";
28 public void attachToSubparser(final Subparser subparser
) {
29 subparser
.help("Show a list of known contacts with names and profiles.");
30 subparser
.addArgument("recipient").help("Specify one ore more phone numbers to show.").nargs("*");
31 subparser
.addArgument("-a", "--all-recipients")
32 .action(Arguments
.storeTrue())
33 .help("Include all known recipients, not only contacts.");
34 subparser
.addArgument("--blocked")
36 .help("Specify if only blocked or unblocked contacts should be shown (default: all contacts)");
37 subparser
.addArgument("--name").help("Find contacts with the given contact or profile name.");
41 public void handleCommand(
42 final Namespace ns
, final Manager m
, final OutputWriter outputWriter
43 ) throws CommandException
{
44 final var allRecipients
= Boolean
.TRUE
.equals(ns
.getBoolean("all-recipients"));
45 final var blocked
= ns
.getBoolean("blocked");
46 final var recipientStrings
= ns
.<String
>getList("recipient");
47 final var recipientIdentifiers
= CommandUtil
.getSingleRecipientIdentifiers(recipientStrings
, m
.getSelfNumber());
48 final var name
= ns
.getString("name");
49 final var recipients
= m
.getRecipients(!allRecipients
,
50 Optional
.ofNullable(blocked
),
52 Optional
.ofNullable(name
));
54 if (outputWriter
instanceof PlainTextWriter writer
) {
55 for (var r
: recipients
) {
56 final var contact
= r
.getContact() == null ? Contact
.newBuilder().build() : r
.getContact();
57 final var profile
= r
.getProfile() == null ? Profile
.newBuilder().build() : r
.getProfile();
59 "Number: {} Name: {} Profile name: {} Username: {} Color: {} Blocked: {} Message expiration: {}",
60 r
.getAddress().getLegacyIdentifier(),
62 profile
.getDisplayName(),
63 r
.getAddress().username().orElse(""),
66 contact
.getMessageExpirationTime() == 0
68 : contact
.getMessageExpirationTime() + "s");
71 final var writer
= (JsonWriter
) outputWriter
;
72 final var jsonContacts
= recipients
.stream().map(r
-> {
73 final var address
= r
.getAddress();
74 final var contact
= r
.getContact() == null ? Contact
.newBuilder().build() : r
.getContact();
75 return new JsonContact(address
.number().orElse(null),
76 address
.uuid().map(UUID
::toString
).orElse(null),
77 address
.username().orElse(null),
81 contact
.getMessageExpirationTime(),
82 r
.getProfile() == null
84 : new JsonContact
.JsonProfile(r
.getProfile().getLastUpdateTimestamp(),
85 r
.getProfile().getGivenName(),
86 r
.getProfile().getFamilyName(),
87 r
.getProfile().getAbout(),
88 r
.getProfile().getAboutEmoji(),
89 r
.getProfile().getMobileCoinAddress() == null
92 .encodeToString(r
.getProfile().getMobileCoinAddress())));
95 writer
.write(jsonContacts
);
99 private record JsonContact(
106 int messageExpirationTime
,
110 private record JsonProfile(
111 long lastUpdateTimestamp
,
116 String mobileCoinAddress