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