1 package org
.asamk
.signal
.manager
.storage
.recipients
;
3 import org
.whispersystems
.signalservice
.api
.push
.PNI
;
4 import org
.whispersystems
.signalservice
.api
.push
.ServiceId
;
5 import org
.whispersystems
.signalservice
.api
.push
.SignalServiceAddress
;
7 import java
.util
.Optional
;
9 public record RecipientAddress(Optional
<ServiceId
> serviceId
, Optional
<PNI
> pni
, Optional
<String
> number
) {
12 * Construct a RecipientAddress.
14 * @param serviceId The ACI or PNI of the user, if available.
15 * @param number The phone number of the user, if available.
17 public RecipientAddress
{
18 if (serviceId
.isPresent() && serviceId
.get().equals(ServiceId
.UNKNOWN
)) {
19 serviceId
= Optional
.empty();
21 if (pni
.isPresent() && pni
.get().equals(ServiceId
.UNKNOWN
)) {
22 pni
= Optional
.empty();
24 if (serviceId
.isEmpty() && pni
.isPresent()) {
25 serviceId
= Optional
.of(pni
.get());
27 if (serviceId
.isPresent() && serviceId
.get() instanceof PNI sPNI
) {
28 if (pni
.isPresent() && !sPNI
.equals(pni
.get())) {
29 throw new AssertionError("Must not have two different PNIs!");
32 pni
= Optional
.of(sPNI
);
35 if (serviceId
.isEmpty() && number
.isEmpty()) {
36 throw new AssertionError("Must have either a ServiceId or E164 number!");
40 public RecipientAddress(Optional
<ServiceId
> serviceId
, Optional
<String
> number
) {
41 this(serviceId
, Optional
.empty(), number
);
44 public RecipientAddress(ServiceId serviceId
, String e164
) {
45 this(Optional
.ofNullable(serviceId
), Optional
.empty(), Optional
.ofNullable(e164
));
48 public RecipientAddress(ServiceId serviceId
, PNI pni
, String e164
) {
49 this(Optional
.ofNullable(serviceId
), Optional
.ofNullable(pni
), Optional
.ofNullable(e164
));
52 public RecipientAddress(SignalServiceAddress address
) {
53 this(Optional
.of(address
.getServiceId()), Optional
.empty(), address
.getNumber());
56 public RecipientAddress(org
.asamk
.signal
.manager
.api
.RecipientAddress address
) {
57 this(address
.uuid().map(ServiceId
::from
), Optional
.empty(), address
.number());
60 public RecipientAddress(ServiceId serviceId
) {
61 this(Optional
.of(serviceId
), Optional
.empty());
64 public RecipientAddress
withIdentifiersFrom(RecipientAddress address
) {
65 return new RecipientAddress((
66 this.serviceId
.isEmpty() || this.isServiceIdPNI() || this.serviceId
.equals(address
.pni
)
67 ) && !address
.isServiceIdPNI() ? address
.serviceId
: this.serviceId
,
68 address
.pni
.or(this::pni
),
69 address
.number
.or(this::number
));
72 public RecipientAddress
removeIdentifiersFrom(RecipientAddress address
) {
73 return new RecipientAddress(address
.serviceId
.equals(this.serviceId
) || address
.pni
.equals(this.serviceId
)
76 address
.pni
.equals(this.pni
) || address
.serviceId
.equals(this.pni
) ? Optional
.empty() : this.pni
,
77 address
.number
.equals(this.number
) ? Optional
.empty() : this.number
);
80 public ServiceId
getServiceId() {
81 return serviceId
.orElse(ServiceId
.UNKNOWN
);
84 public String
getIdentifier() {
85 if (serviceId
.isPresent()) {
86 return serviceId
.get().toString();
87 } else if (number
.isPresent()) {
90 throw new AssertionError("Given the checks in the constructor, this should not be possible.");
94 public String
getLegacyIdentifier() {
95 if (number
.isPresent()) {
97 } else if (serviceId
.isPresent()) {
98 return serviceId
.get().toString();
100 throw new AssertionError("Given the checks in the constructor, this should not be possible.");
104 public boolean matches(RecipientAddress other
) {
105 return (serviceId
.isPresent() && other
.serviceId
.isPresent() && serviceId
.get().equals(other
.serviceId
.get()))
107 pni
.isPresent() && other
.serviceId
.isPresent() && pni
.get().equals(other
.serviceId
.get())
110 serviceId
.isPresent() && other
.pni
.isPresent() && serviceId
.get().equals(other
.pni
.get())
113 pni
.isPresent() && other
.pni
.isPresent() && pni
.get().equals(other
.pni
.get())
116 number
.isPresent() && other
.number
.isPresent() && number
.get().equals(other
.number
.get())
120 public boolean hasSingleIdentifier() {
121 return serviceId().isEmpty() || number
.isEmpty();
124 public boolean hasIdentifiersOf(RecipientAddress address
) {
125 return (address
.serviceId
.isEmpty() || address
.serviceId
.equals(serviceId
) || address
.serviceId
.equals(pni
))
126 && (address
.pni
.isEmpty() || address
.pni
.equals(pni
))
127 && (address
.number
.isEmpty() || address
.number
.equals(number
));
130 public boolean hasAdditionalIdentifiersThan(RecipientAddress address
) {
132 serviceId
.isPresent() && (
133 address
.serviceId
.isEmpty() || (
134 !address
.serviceId
.equals(serviceId
) && !address
.pni
.equals(serviceId
)
138 pni
.isPresent() && !address
.serviceId
.equals(pni
) && (
139 address
.pni
.isEmpty() || !address
.pni
.equals(pni
)
142 number
.isPresent() && (
143 address
.number
.isEmpty() || !address
.number
.equals(number
)
148 public boolean hasOnlyPniAndNumber() {
149 return pni
.isPresent() && serviceId
.equals(pni
) && number
.isPresent();
152 public boolean isServiceIdPNI() {
153 return serviceId
.isPresent() && (pni
.isPresent() && serviceId
.equals(pni
));
156 public SignalServiceAddress
toSignalServiceAddress() {
157 return new SignalServiceAddress(getServiceId(), number
);
160 public org
.asamk
.signal
.manager
.api
.RecipientAddress
toApiRecipientAddress() {
161 return new org
.asamk
.signal
.manager
.api
.RecipientAddress(serviceId().map(ServiceId
::uuid
), number());