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
<ACI
> aci
, Optional
<PNI
> pni
, Optional
<String
> number
, Optional
<String
> username
15 * Construct a RecipientAddress.
17 * @param aci The ACI of the user, if available.
18 * @param pni The PNI of the user, if available.
19 * @param number The phone number of the user, if available.
20 * @param username The username of the user, if available.
22 public RecipientAddress
{
23 if (aci
.isPresent() && aci
.get().isUnknown()) {
24 aci
= Optional
.empty();
26 if (pni
.isPresent() && pni
.get().isUnknown()) {
27 pni
= Optional
.empty();
29 if (aci
.isEmpty() && pni
.isEmpty() && number
.isEmpty() && username
.isEmpty()) {
30 throw new AssertionError("Must have either a ServiceId, username or E164 number!");
34 public RecipientAddress(Optional
<ServiceId
> serviceId
, Optional
<String
> number
) {
35 this(serviceId
.filter(s
-> s
instanceof ACI
).map(s
-> (ACI
) s
),
36 serviceId
.filter(s
-> s
instanceof PNI
).map(s
-> (PNI
) s
),
41 public RecipientAddress(ACI aci
, String e164
) {
42 this(Optional
.ofNullable(aci
), Optional
.empty(), Optional
.ofNullable(e164
), Optional
.empty());
45 public RecipientAddress(PNI pni
, String e164
) {
46 this(Optional
.empty(), Optional
.ofNullable(pni
), Optional
.ofNullable(e164
), Optional
.empty());
49 public RecipientAddress(String e164
) {
50 this(Optional
.empty(), Optional
.empty(), Optional
.ofNullable(e164
), Optional
.empty());
53 public RecipientAddress(ACI aci
, PNI pni
, String e164
) {
54 this(Optional
.ofNullable(aci
), Optional
.ofNullable(pni
), Optional
.ofNullable(e164
), Optional
.empty());
57 public RecipientAddress(ACI aci
, PNI pni
, String e164
, String username
) {
58 this(Optional
.ofNullable(aci
),
59 Optional
.ofNullable(pni
),
60 Optional
.ofNullable(e164
),
61 Optional
.ofNullable(username
));
64 public RecipientAddress(SignalServiceAddress address
) {
65 this(address
.getServiceId() instanceof ACI ? Optional
.of((ACI
) address
.getServiceId()) : Optional
.empty(),
66 address
.getServiceId() instanceof PNI ? Optional
.of((PNI
) address
.getServiceId()) : Optional
.empty(),
71 public RecipientAddress(org
.asamk
.signal
.manager
.api
.RecipientAddress address
) {
72 this(address
.aci().map(ACI
::parseOrNull
),
73 address
.pni().map(PNI
::parseOrNull
),
78 public RecipientAddress(ServiceId serviceId
) {
79 this(Optional
.of(serviceId
), Optional
.empty());
82 public RecipientAddress
withIdentifiersFrom(RecipientAddress address
) {
83 return new RecipientAddress(address
.aci
.or(this::aci
),
84 address
.pni
.or(this::pni
),
85 address
.number
.or(this::number
),
86 address
.username
.or(this::username
));
89 public RecipientAddress
removeIdentifiersFrom(RecipientAddress address
) {
90 return new RecipientAddress(address
.aci
.equals(this.aci
) ? Optional
.empty() : this.aci
,
91 address
.pni
.equals(this.pni
) ? Optional
.empty() : this.pni
,
92 address
.number
.equals(this.number
) ? Optional
.empty() : this.number
,
93 address
.username
.equals(this.username
) ? Optional
.empty() : this.username
);
96 public Optional
<ServiceId
> serviceId() {
97 return aci
.map(aci
-> (ServiceId
) aci
).or(this::pni
);
100 public String
getIdentifier() {
101 if (aci
.isPresent()) {
102 return aci
.get().toString();
103 } else if (pni
.isPresent()) {
104 return pni
.get().toString();
105 } else if (number
.isPresent()) {
108 throw new AssertionError("Given the checks in the constructor, this should not be possible.");
112 public String
getLegacyIdentifier() {
113 if (number
.isPresent()) {
115 } else if (aci
.isPresent()) {
116 return aci
.get().toString();
117 } else if (pni
.isPresent()) {
118 return pni
.get().toString();
120 throw new AssertionError("Given the checks in the constructor, this should not be possible.");
124 public boolean matches(RecipientAddress other
) {
125 return (aci
.isPresent() && other
.aci
.isPresent() && aci
.get().equals(other
.aci
.get())) || (
126 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
= aci().map(s
-> 1).orElse(0) + pni().map(s
-> 1).orElse(0) + number().map(s
-> 1)
134 .orElse(0) + username().map(s
-> 1).orElse(0);
135 return identifiersCount
== 1;
138 public boolean hasIdentifiersOf(RecipientAddress address
) {
139 return (address
.aci
.isEmpty() || address
.aci
.equals(aci
))
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
) {
148 address
.aci
.isEmpty() || !address
.aci
.equals(aci
)
153 address
.pni
.isEmpty() || !address
.pni
.equals(pni
)
156 number
.isPresent() && (
157 address
.number
.isEmpty() || !address
.number
.equals(number
)
160 username
.isPresent() && (
161 address
.username
.isEmpty() || !address
.username
.equals(username
)
166 public boolean hasOnlyPniAndNumber() {
167 return pni
.isPresent() && aci
.isEmpty() && number
.isPresent();
170 public SignalServiceAddress
toSignalServiceAddress() {
171 return new SignalServiceAddress(serviceId().orElse(ACI
.UNKNOWN
), number
);
174 public org
.asamk
.signal
.manager
.api
.RecipientAddress
toApiRecipientAddress() {
175 return new org
.asamk
.signal
.manager
.api
.RecipientAddress(aci().map(ServiceId
::toString
),
176 pni().map(ServiceId
::toString
),