"queryAllDeclaredConstructors":true,
"methods":[{"name":"id","parameterTypes":[] }, {"name":"opaque","parameterTypes":[] }, {"name":"sdp","parameterTypes":[] }, {"name":"type","parameterTypes":[] }]
},
+{
+ "name":"org.asamk.signal.json.JsonContact",
+ "allDeclaredFields":true,
+ "queryAllDeclaredMethods":true,
+ "methods":[{"name":"color","parameterTypes":[] }, {"name":"familyName","parameterTypes":[] }, {"name":"givenName","parameterTypes":[] }, {"name":"internal","parameterTypes":[] }, {"name":"isBlocked","parameterTypes":[] }, {"name":"isHidden","parameterTypes":[] }, {"name":"messageExpirationTime","parameterTypes":[] }, {"name":"name","parameterTypes":[] }, {"name":"nickFamilyName","parameterTypes":[] }, {"name":"nickGivenName","parameterTypes":[] }, {"name":"nickName","parameterTypes":[] }, {"name":"note","parameterTypes":[] }, {"name":"number","parameterTypes":[] }, {"name":"profile","parameterTypes":[] }, {"name":"profileSharing","parameterTypes":[] }, {"name":"unregistered","parameterTypes":[] }, {"name":"username","parameterTypes":[] }, {"name":"uuid","parameterTypes":[] }]
+},
+{
+ "name":"org.asamk.signal.json.JsonContact$JsonInternal",
+ "allDeclaredFields":true,
+ "queryAllDeclaredMethods":true,
+ "methods":[{"name":"capabilities","parameterTypes":[] }, {"name":"discoverableByPhonenumber","parameterTypes":[] }, {"name":"sharesPhoneNumber","parameterTypes":[] }, {"name":"unidentifiedAccessMode","parameterTypes":[] }]
+},
+{
+ "name":"org.asamk.signal.json.JsonContact$JsonProfile",
+ "allDeclaredFields":true,
+ "queryAllDeclaredMethods":true,
+ "methods":[{"name":"about","parameterTypes":[] }, {"name":"aboutEmoji","parameterTypes":[] }, {"name":"familyName","parameterTypes":[] }, {"name":"givenName","parameterTypes":[] }, {"name":"hasAvatar","parameterTypes":[] }, {"name":"lastUpdateTimestamp","parameterTypes":[] }, {"name":"mobileCoinAddress","parameterTypes":[] }]
+},
{
"name":"org.asamk.signal.json.JsonContactAddress",
"allDeclaredFields":true,
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;
.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
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: {} Name: {} Profile name: {} Username: {} Color: {} Blocked: {} Message expiration: {}",
- r.getAddress().getLegacyIdentifier(),
+ "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(""),
- contact.color(),
+ 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().getFamilyName(),
r.getProfile().getAbout(),
r.getProfile().getAboutEmoji(),
+ r.getProfile().getAvatarUrlPath() != null,
r.getProfile().getMobileCoinAddress() == null
? null
: Base64.getEncoder()
- .encodeToString(r.getProfile().getMobileCoinAddress())));
+ .encodeToString(r.getProfile().getMobileCoinAddress())),
+ jsonInternal);
}).toList();
writer.write(jsonContacts);
}
}
}
-
- private record JsonContact(
- String number,
- String uuid,
- String username,
- String name,
- String color,
- boolean isBlocked,
- int messageExpirationTime,
- JsonProfile profile
- ) {
-
- private record JsonProfile(
- long lastUpdateTimestamp,
- String givenName,
- String familyName,
- String about,
- String aboutEmoji,
- String mobileCoinAddress
- ) {}
- }
}