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
.uuid().map(ACI
::from
), Optional
.empty(), address
.number(), address
.username());
75 public RecipientAddress(ServiceId serviceId
) {
76 this(Optional
.of(serviceId
), Optional
.empty());
79 public RecipientAddress
withIdentifiersFrom(RecipientAddress address
) {
80 return new RecipientAddress(address
.aci
.or(this::aci
),
81 address
.pni
.or(this::pni
),
82 address
.number
.or(this::number
),
83 address
.username
.or(this::username
));
86 public RecipientAddress
removeIdentifiersFrom(RecipientAddress address
) {
87 return new RecipientAddress(address
.aci
.equals(this.aci
) ? Optional
.empty() : this.aci
,
88 address
.pni
.equals(this.pni
) ? Optional
.empty() : this.pni
,
89 address
.number
.equals(this.number
) ? Optional
.empty() : this.number
,
90 address
.username
.equals(this.username
) ? Optional
.empty() : this.username
);
93 public Optional
<ServiceId
> serviceId() {
94 return aci
.map(aci
-> (ServiceId
) aci
).or(this::pni
);
97 public String
getIdentifier() {
98 if (aci
.isPresent()) {
99 return aci
.get().toString();
100 } else if (pni
.isPresent()) {
101 return pni
.get().toString();
102 } else if (number
.isPresent()) {
105 throw new AssertionError("Given the checks in the constructor, this should not be possible.");
109 public String
getLegacyIdentifier() {
110 if (number
.isPresent()) {
112 } else if (aci
.isPresent()) {
113 return aci
.get().toString();
114 } else if (pni
.isPresent()) {
115 return pni
.get().toString();
117 throw new AssertionError("Given the checks in the constructor, this should not be possible.");
121 public boolean matches(RecipientAddress other
) {
122 return (aci
.isPresent() && other
.aci
.isPresent() && aci
.get().equals(other
.aci
.get())) || (
123 pni
.isPresent() && other
.pni
.isPresent() && pni
.get().equals(other
.pni
.get())
125 number
.isPresent() && other
.number
.isPresent() && number
.get().equals(other
.number
.get())
129 public boolean hasSingleIdentifier() {
130 final var identifiersCount
= aci().map(s
-> 1).orElse(0) + pni().map(s
-> 1).orElse(0) + number().map(s
-> 1)
131 .orElse(0) + username().map(s
-> 1).orElse(0);
132 return identifiersCount
== 1;
135 public boolean hasIdentifiersOf(RecipientAddress address
) {
136 return (address
.aci
.isEmpty() || address
.aci
.equals(aci
))
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
) {
145 address
.aci
.isEmpty() || !address
.aci
.equals(aci
)
150 address
.pni
.isEmpty() || !address
.pni
.equals(pni
)
153 number
.isPresent() && (
154 address
.number
.isEmpty() || !address
.number
.equals(number
)
157 username
.isPresent() && (
158 address
.username
.isEmpty() || !address
.username
.equals(username
)
163 public boolean hasOnlyPniAndNumber() {
164 return pni
.isPresent() && aci
.isEmpty() && number
.isPresent();
167 public SignalServiceAddress
toSignalServiceAddress() {
168 return new SignalServiceAddress(serviceId().orElse(ACI
.UNKNOWN
), number
);
171 public org
.asamk
.signal
.manager
.api
.RecipientAddress
toApiRecipientAddress() {
172 return new org
.asamk
.signal
.manager
.api
.RecipientAddress(serviceId().map(ServiceId
::getRawUuid
),