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(
10 Optional
<ServiceId
> serviceId
, Optional
<PNI
> pni
, Optional
<String
> number
, Optional
<String
> username
14 * Construct a RecipientAddress.
16 * @param serviceId The ACI or PNI of the user, if available.
17 * @param number The phone number of the user, if available.
19 public RecipientAddress
{
20 if (serviceId
.isPresent() && serviceId
.get().equals(ServiceId
.UNKNOWN
)) {
21 serviceId
= Optional
.empty();
23 if (pni
.isPresent() && pni
.get().equals(ServiceId
.UNKNOWN
)) {
24 pni
= Optional
.empty();
26 if (serviceId
.isEmpty() && pni
.isPresent()) {
27 serviceId
= Optional
.of(pni
.get());
29 if (serviceId
.isPresent() && serviceId
.get() instanceof PNI sPNI
) {
30 if (pni
.isPresent() && !sPNI
.equals(pni
.get())) {
31 throw new AssertionError("Must not have two different PNIs!");
34 pni
= Optional
.of(sPNI
);
37 if (serviceId
.isEmpty() && number
.isEmpty()) {
38 throw new AssertionError("Must have either a ServiceId or E164 number!");
42 public RecipientAddress(Optional
<ServiceId
> serviceId
, Optional
<String
> number
) {
43 this(serviceId
, Optional
.empty(), number
, Optional
.empty());
46 public RecipientAddress(ServiceId serviceId
, String e164
) {
47 this(Optional
.ofNullable(serviceId
), Optional
.empty(), Optional
.ofNullable(e164
), Optional
.empty());
50 public RecipientAddress(ServiceId serviceId
, PNI pni
, String e164
) {
51 this(Optional
.ofNullable(serviceId
), Optional
.ofNullable(pni
), Optional
.ofNullable(e164
), Optional
.empty());
54 public RecipientAddress(ServiceId serviceId
, PNI pni
, String e164
, String username
) {
55 this(Optional
.ofNullable(serviceId
),
56 Optional
.ofNullable(pni
),
57 Optional
.ofNullable(e164
),
58 Optional
.ofNullable(username
));
61 public RecipientAddress(SignalServiceAddress address
) {
62 this(Optional
.of(address
.getServiceId()), Optional
.empty(), address
.getNumber(), Optional
.empty());
65 public RecipientAddress(org
.asamk
.signal
.manager
.api
.RecipientAddress address
) {
66 this(address
.uuid().map(ServiceId
::from
), Optional
.empty(), address
.number(), address
.username());
69 public RecipientAddress(ServiceId serviceId
) {
70 this(Optional
.of(serviceId
), Optional
.empty());
73 public RecipientAddress
withIdentifiersFrom(RecipientAddress address
) {
74 return new RecipientAddress((
75 this.serviceId
.isEmpty() || this.isServiceIdPNI() || this.serviceId
.equals(address
.pni
)
76 ) && !address
.isServiceIdPNI() ? address
.serviceId
: this.serviceId
,
77 address
.pni
.or(this::pni
),
78 address
.number
.or(this::number
),
79 address
.username
.or(this::username
));
82 public RecipientAddress
removeIdentifiersFrom(RecipientAddress address
) {
83 return new RecipientAddress(address
.serviceId
.equals(this.serviceId
) || address
.pni
.equals(this.serviceId
)
86 address
.pni
.equals(this.pni
) || address
.serviceId
.equals(this.pni
) ? Optional
.empty() : this.pni
,
87 address
.number
.equals(this.number
) ? Optional
.empty() : this.number
,
88 address
.username
.equals(this.username
) ? Optional
.empty() : this.username
);
91 public ServiceId
getServiceId() {
92 return serviceId
.orElse(ServiceId
.UNKNOWN
);
95 public String
getIdentifier() {
96 if (serviceId
.isPresent()) {
97 return serviceId
.get().toString();
98 } else if (number
.isPresent()) {
101 throw new AssertionError("Given the checks in the constructor, this should not be possible.");
105 public String
getLegacyIdentifier() {
106 if (number
.isPresent()) {
108 } else if (serviceId
.isPresent()) {
109 return serviceId
.get().toString();
111 throw new AssertionError("Given the checks in the constructor, this should not be possible.");
115 public boolean matches(RecipientAddress other
) {
116 return (serviceId
.isPresent() && other
.serviceId
.isPresent() && serviceId
.get().equals(other
.serviceId
.get()))
118 pni
.isPresent() && other
.serviceId
.isPresent() && pni
.get().equals(other
.serviceId
.get())
121 serviceId
.isPresent() && other
.pni
.isPresent() && serviceId
.get().equals(other
.pni
.get())
124 pni
.isPresent() && other
.pni
.isPresent() && pni
.get().equals(other
.pni
.get())
127 number
.isPresent() && other
.number
.isPresent() && number
.get().equals(other
.number
.get())
131 public boolean hasSingleIdentifier() {
132 final var identifiersCount
= serviceId().map(s
-> 1).orElse(0)
133 + number().map(s
-> 1).orElse(0)
134 + username().map(s
-> 1).orElse(0);
135 return identifiersCount
== 1;
138 public boolean hasIdentifiersOf(RecipientAddress address
) {
139 return (address
.serviceId
.isEmpty() || address
.serviceId
.equals(serviceId
) || address
.serviceId
.equals(pni
))
140 && (address
.pni
.isEmpty() || address
.pni
.equals(pni
))
141 && (address
.number
.isEmpty() || address
.number
.equals(number
))
142 && (address
.username
.isEmpty() || address
.username
.equals(username
));
145 public boolean hasAdditionalIdentifiersThan(RecipientAddress address
) {
147 serviceId
.isPresent() && (
148 address
.serviceId
.isEmpty() || (
149 !address
.serviceId
.equals(serviceId
) && !address
.pni
.equals(serviceId
)
153 pni
.isPresent() && !address
.serviceId
.equals(pni
) && (
154 address
.pni
.isEmpty() || !address
.pni
.equals(pni
)
157 number
.isPresent() && (
158 address
.number
.isEmpty() || !address
.number
.equals(number
)
161 username
.isPresent() && (
162 address
.username
.isEmpty() || !address
.username
.equals(username
)
167 public boolean hasOnlyPniAndNumber() {
168 return pni
.isPresent() && serviceId
.equals(pni
) && number
.isPresent();
171 public boolean isServiceIdPNI() {
172 return serviceId
.isPresent() && (pni
.isPresent() && serviceId
.equals(pni
));
175 public SignalServiceAddress
toSignalServiceAddress() {
176 return new SignalServiceAddress(getServiceId(), number
);
179 public org
.asamk
.signal
.manager
.api
.RecipientAddress
toApiRecipientAddress() {
180 return new org
.asamk
.signal
.manager
.api
.RecipientAddress(serviceId().map(ServiceId
::uuid
),