]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/storage/recipients/RecipientAddress.java
d94a93a3dd9067a30816f03402e14d2205a06740
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / storage / recipients / RecipientAddress.java
1 package org.asamk.signal.manager.storage.recipients;
2
3 import org.whispersystems.signalservice.api.push.PNI;
4 import org.whispersystems.signalservice.api.push.ServiceId;
5 import org.whispersystems.signalservice.api.push.SignalServiceAddress;
6
7 import java.util.Optional;
8
9 public record RecipientAddress(
10 Optional<ServiceId> serviceId, Optional<PNI> pni, Optional<String> number, Optional<String> username
11 ) {
12
13 /**
14 * Construct a RecipientAddress.
15 *
16 * @param serviceId The ACI or PNI of the user, if available.
17 * @param number The phone number of the user, if available.
18 */
19 public RecipientAddress {
20 if (serviceId.isPresent() && serviceId.get().equals(ServiceId.UNKNOWN)) {
21 serviceId = Optional.empty();
22 }
23 if (pni.isPresent() && pni.get().equals(ServiceId.UNKNOWN)) {
24 pni = Optional.empty();
25 }
26 if (serviceId.isEmpty() && pni.isPresent()) {
27 serviceId = Optional.of(pni.get());
28 }
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!");
32 }
33 if (pni.isEmpty()) {
34 pni = Optional.of(sPNI);
35 }
36 }
37 if (serviceId.isEmpty() && number.isEmpty()) {
38 throw new AssertionError("Must have either a ServiceId or E164 number!");
39 }
40 }
41
42 public RecipientAddress(Optional<ServiceId> serviceId, Optional<String> number) {
43 this(serviceId, Optional.empty(), number, Optional.empty());
44 }
45
46 public RecipientAddress(ServiceId serviceId, String e164) {
47 this(Optional.ofNullable(serviceId), Optional.empty(), Optional.ofNullable(e164), Optional.empty());
48 }
49
50 public RecipientAddress(ServiceId serviceId, PNI pni, String e164) {
51 this(Optional.ofNullable(serviceId), Optional.ofNullable(pni), Optional.ofNullable(e164), Optional.empty());
52 }
53
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));
59 }
60
61 public RecipientAddress(SignalServiceAddress address) {
62 this(Optional.of(address.getServiceId()), Optional.empty(), address.getNumber(), Optional.empty());
63 }
64
65 public RecipientAddress(org.asamk.signal.manager.api.RecipientAddress address) {
66 this(address.uuid().map(ServiceId::from), Optional.empty(), address.number(), address.username());
67 }
68
69 public RecipientAddress(ServiceId serviceId) {
70 this(Optional.of(serviceId), Optional.empty());
71 }
72
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));
80 }
81
82 public RecipientAddress removeIdentifiersFrom(RecipientAddress address) {
83 return new RecipientAddress(address.serviceId.equals(this.serviceId) || address.pni.equals(this.serviceId)
84 ? Optional.empty()
85 : 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);
89 }
90
91 public ServiceId getServiceId() {
92 return serviceId.orElse(ServiceId.UNKNOWN);
93 }
94
95 public String getIdentifier() {
96 if (serviceId.isPresent()) {
97 return serviceId.get().toString();
98 } else if (number.isPresent()) {
99 return number.get();
100 } else {
101 throw new AssertionError("Given the checks in the constructor, this should not be possible.");
102 }
103 }
104
105 public String getLegacyIdentifier() {
106 if (number.isPresent()) {
107 return number.get();
108 } else if (serviceId.isPresent()) {
109 return serviceId.get().toString();
110 } else {
111 throw new AssertionError("Given the checks in the constructor, this should not be possible.");
112 }
113 }
114
115 public boolean matches(RecipientAddress other) {
116 return (serviceId.isPresent() && other.serviceId.isPresent() && serviceId.get().equals(other.serviceId.get()))
117 || (
118 pni.isPresent() && other.serviceId.isPresent() && pni.get().equals(other.serviceId.get())
119 )
120 || (
121 serviceId.isPresent() && other.pni.isPresent() && serviceId.get().equals(other.pni.get())
122 )
123 || (
124 pni.isPresent() && other.pni.isPresent() && pni.get().equals(other.pni.get())
125 )
126 || (
127 number.isPresent() && other.number.isPresent() && number.get().equals(other.number.get())
128 );
129 }
130
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;
136 }
137
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));
143 }
144
145 public boolean hasAdditionalIdentifiersThan(RecipientAddress address) {
146 return (
147 serviceId.isPresent() && (
148 address.serviceId.isEmpty() || (
149 !address.serviceId.equals(serviceId) && !address.pni.equals(serviceId)
150 )
151 )
152 ) || (
153 pni.isPresent() && !address.serviceId.equals(pni) && (
154 address.pni.isEmpty() || !address.pni.equals(pni)
155 )
156 ) || (
157 number.isPresent() && (
158 address.number.isEmpty() || !address.number.equals(number)
159 )
160 ) || (
161 username.isPresent() && (
162 address.username.isEmpty() || !address.username.equals(username)
163 )
164 );
165 }
166
167 public boolean hasOnlyPniAndNumber() {
168 return pni.isPresent() && serviceId.equals(pni) && number.isPresent();
169 }
170
171 public boolean isServiceIdPNI() {
172 return serviceId.isPresent() && (pni.isPresent() && serviceId.equals(pni));
173 }
174
175 public SignalServiceAddress toSignalServiceAddress() {
176 return new SignalServiceAddress(getServiceId(), number);
177 }
178
179 public org.asamk.signal.manager.api.RecipientAddress toApiRecipientAddress() {
180 return new org.asamk.signal.manager.api.RecipientAddress(serviceId().map(ServiceId::uuid),
181 number(),
182 username());
183 }
184 }