1 package org
.asamk
.signal
.manager
.storage
.recipients
;
3 import org
.whispersystems
.signalservice
.api
.push
.ServiceId
;
4 import org
.whispersystems
.signalservice
.api
.push
.ServiceId
.ACI
;
5 import org
.whispersystems
.signalservice
.api
.push
.ServiceId
.PNI
;
6 import org
.whispersystems
.signalservice
.api
.push
.SignalServiceAddress
;
8 import java
.util
.Optional
;
10 public record RecipientAddress(
11 Optional
<ServiceId
> serviceId
, Optional
<PNI
> pni
, Optional
<String
> number
, Optional
<String
> username
15 * Construct a RecipientAddress.
17 * @param serviceId The ACI or PNI of the user, if available.
18 * @param number The phone number of the user, if available.
20 public RecipientAddress
{
21 if (serviceId
.isPresent() && serviceId
.get().isUnknown()) {
22 serviceId
= Optional
.empty();
24 if (pni
.isPresent() && pni
.get().isUnknown()) {
25 pni
= Optional
.empty();
27 if (serviceId
.isEmpty() && pni
.isPresent()) {
28 serviceId
= Optional
.of(pni
.get());
30 if (serviceId
.isPresent() && serviceId
.get() instanceof PNI sPNI
) {
31 if (pni
.isPresent() && !sPNI
.equals(pni
.get())) {
32 throw new AssertionError("Must not have two different PNIs!");
35 pni
= Optional
.of(sPNI
);
38 if (serviceId
.isEmpty() && number
.isEmpty()) {
39 throw new AssertionError("Must have either a ServiceId or E164 number!");
43 public RecipientAddress(Optional
<ServiceId
> serviceId
, Optional
<String
> number
) {
44 this(serviceId
, Optional
.empty(), number
, Optional
.empty());
47 public RecipientAddress(ServiceId serviceId
, String e164
) {
48 this(Optional
.ofNullable(serviceId
), Optional
.empty(), Optional
.ofNullable(e164
), Optional
.empty());
51 public RecipientAddress(ServiceId serviceId
, PNI pni
, String e164
) {
52 this(Optional
.ofNullable(serviceId
), Optional
.ofNullable(pni
), Optional
.ofNullable(e164
), Optional
.empty());
55 public RecipientAddress(ServiceId serviceId
, PNI pni
, String e164
, String username
) {
56 this(Optional
.ofNullable(serviceId
),
57 Optional
.ofNullable(pni
),
58 Optional
.ofNullable(e164
),
59 Optional
.ofNullable(username
));
62 public RecipientAddress(SignalServiceAddress address
) {
63 this(Optional
.of(address
.getServiceId()), Optional
.empty(), address
.getNumber(), Optional
.empty());
66 public RecipientAddress(org
.asamk
.signal
.manager
.api
.RecipientAddress address
) {
67 this(address
.uuid().map(ACI
::from
), Optional
.empty(), address
.number(), address
.username());
70 public RecipientAddress(ServiceId serviceId
) {
71 this(Optional
.of(serviceId
), Optional
.empty());
74 public RecipientAddress
withIdentifiersFrom(RecipientAddress address
) {
75 return new RecipientAddress((
76 this.serviceId
.isEmpty() || this.isServiceIdPNI() || this.serviceId
.equals(address
.pni
)
77 ) && !address
.isServiceIdPNI() ? address
.serviceId
: this.serviceId
,
78 address
.pni
.or(this::pni
),
79 address
.number
.or(this::number
),
80 address
.username
.or(this::username
));
83 public RecipientAddress
removeIdentifiersFrom(RecipientAddress address
) {
84 return new RecipientAddress(address
.serviceId
.equals(this.serviceId
) || address
.pni
.equals(this.serviceId
)
87 address
.pni
.equals(this.pni
) || address
.serviceId
.equals(this.pni
) ? Optional
.empty() : this.pni
,
88 address
.number
.equals(this.number
) ? Optional
.empty() : this.number
,
89 address
.username
.equals(this.username
) ? Optional
.empty() : this.username
);
92 public Optional
<ACI
> aci() {
93 return serviceId
.map(s
-> s
instanceof ServiceId
.ACI aci ? aci
: null);
96 public String
getIdentifier() {
97 if (serviceId
.isPresent()) {
98 return serviceId
.get().toString();
99 } else if (number
.isPresent()) {
102 throw new AssertionError("Given the checks in the constructor, this should not be possible.");
106 public String
getLegacyIdentifier() {
107 if (number
.isPresent()) {
109 } else if (serviceId
.isPresent()) {
110 return serviceId
.get().toString();
112 throw new AssertionError("Given the checks in the constructor, this should not be possible.");
116 public boolean matches(RecipientAddress other
) {
117 return (serviceId
.isPresent() && other
.serviceId
.isPresent() && serviceId
.get().equals(other
.serviceId
.get()))
119 pni
.isPresent() && other
.serviceId
.isPresent() && pni
.get().equals(other
.serviceId
.get())
122 serviceId
.isPresent() && other
.pni
.isPresent() && serviceId
.get().equals(other
.pni
.get())
125 pni
.isPresent() && other
.pni
.isPresent() && pni
.get().equals(other
.pni
.get())
128 number
.isPresent() && other
.number
.isPresent() && number
.get().equals(other
.number
.get())
132 public boolean hasSingleIdentifier() {
133 final var identifiersCount
= serviceId().map(s
-> 1).orElse(0)
134 + number().map(s
-> 1).orElse(0)
135 + username().map(s
-> 1).orElse(0);
136 return identifiersCount
== 1;
139 public boolean hasIdentifiersOf(RecipientAddress address
) {
140 return (address
.serviceId
.isEmpty() || address
.serviceId
.equals(serviceId
) || address
.serviceId
.equals(pni
))
141 && (address
.pni
.isEmpty() || address
.pni
.equals(pni
))
142 && (address
.number
.isEmpty() || address
.number
.equals(number
))
143 && (address
.username
.isEmpty() || address
.username
.equals(username
));
146 public boolean hasAdditionalIdentifiersThan(RecipientAddress address
) {
148 serviceId
.isPresent() && (
149 address
.serviceId
.isEmpty() || (
150 !address
.serviceId
.equals(serviceId
) && !address
.pni
.equals(serviceId
)
154 pni
.isPresent() && !address
.serviceId
.equals(pni
) && (
155 address
.pni
.isEmpty() || !address
.pni
.equals(pni
)
158 number
.isPresent() && (
159 address
.number
.isEmpty() || !address
.number
.equals(number
)
162 username
.isPresent() && (
163 address
.username
.isEmpty() || !address
.username
.equals(username
)
168 public boolean hasOnlyPniAndNumber() {
169 return pni
.isPresent() && serviceId
.equals(pni
) && number
.isPresent();
172 public boolean isServiceIdPNI() {
173 return serviceId
.isPresent() && (pni
.isPresent() && serviceId
.equals(pni
));
176 public SignalServiceAddress
toSignalServiceAddress() {
177 return new SignalServiceAddress(serviceId
.orElse(ACI
.UNKNOWN
), number
);
180 public org
.asamk
.signal
.manager
.api
.RecipientAddress
toApiRecipientAddress() {
181 return new org
.asamk
.signal
.manager
.api
.RecipientAddress(serviceId().map(ServiceId
::getRawUuid
),