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 String
getIdentifier() {
93 if (serviceId
.isPresent()) {
94 return serviceId
.get().toString();
95 } else if (number
.isPresent()) {
98 throw new AssertionError("Given the checks in the constructor, this should not be possible.");
102 public String
getLegacyIdentifier() {
103 if (number
.isPresent()) {
105 } else if (serviceId
.isPresent()) {
106 return serviceId
.get().toString();
108 throw new AssertionError("Given the checks in the constructor, this should not be possible.");
112 public boolean matches(RecipientAddress other
) {
113 return (serviceId
.isPresent() && other
.serviceId
.isPresent() && serviceId
.get().equals(other
.serviceId
.get()))
115 pni
.isPresent() && other
.serviceId
.isPresent() && pni
.get().equals(other
.serviceId
.get())
118 serviceId
.isPresent() && other
.pni
.isPresent() && serviceId
.get().equals(other
.pni
.get())
121 pni
.isPresent() && other
.pni
.isPresent() && pni
.get().equals(other
.pni
.get())
124 number
.isPresent() && other
.number
.isPresent() && number
.get().equals(other
.number
.get())
128 public boolean hasSingleIdentifier() {
129 final var identifiersCount
= serviceId().map(s
-> 1).orElse(0)
130 + number().map(s
-> 1).orElse(0)
131 + username().map(s
-> 1).orElse(0);
132 return identifiersCount
== 1;
135 public boolean hasIdentifiersOf(RecipientAddress address
) {
136 return (address
.serviceId
.isEmpty() || address
.serviceId
.equals(serviceId
) || address
.serviceId
.equals(pni
))
137 && (address
.pni
.isEmpty() || address
.pni
.equals(pni
))
138 && (address
.number
.isEmpty() || address
.number
.equals(number
))
139 && (address
.username
.isEmpty() || address
.username
.equals(username
));
142 public boolean hasAdditionalIdentifiersThan(RecipientAddress address
) {
144 serviceId
.isPresent() && (
145 address
.serviceId
.isEmpty() || (
146 !address
.serviceId
.equals(serviceId
) && !address
.pni
.equals(serviceId
)
150 pni
.isPresent() && !address
.serviceId
.equals(pni
) && (
151 address
.pni
.isEmpty() || !address
.pni
.equals(pni
)
154 number
.isPresent() && (
155 address
.number
.isEmpty() || !address
.number
.equals(number
)
158 username
.isPresent() && (
159 address
.username
.isEmpty() || !address
.username
.equals(username
)
164 public boolean hasOnlyPniAndNumber() {
165 return pni
.isPresent() && serviceId
.equals(pni
) && number
.isPresent();
168 public boolean isServiceIdPNI() {
169 return serviceId
.isPresent() && (pni
.isPresent() && serviceId
.equals(pni
));
172 public SignalServiceAddress
toSignalServiceAddress() {
173 return new SignalServiceAddress(serviceId
.orElse(ACI
.UNKNOWN
), number
);
176 public org
.asamk
.signal
.manager
.api
.RecipientAddress
toApiRecipientAddress() {
177 return new org
.asamk
.signal
.manager
.api
.RecipientAddress(serviceId().map(ServiceId
::getRawUuid
),