mirror of
https://github.com/AsamK/signal-cli
synced 2025-08-29 10:30:38 +00:00
Store group member uuids in group store
The member list is now stored as a mixed list of strings and objects, e.g.: "members": [ "+XXXX", { "number": "+XXXX", "uuid": "XXX-XX" } ]
This commit is contained in:
parent
a4e1d69788
commit
f982d2752e
5 changed files with 159 additions and 61 deletions
|
@ -19,7 +19,7 @@ public interface Signal extends DBusInterface {
|
||||||
|
|
||||||
void sendEndSessionMessage(List<String> recipients) throws IOException, EncapsulatedExceptions, InvalidNumberException;
|
void sendEndSessionMessage(List<String> recipients) throws IOException, EncapsulatedExceptions, InvalidNumberException;
|
||||||
|
|
||||||
void sendGroupMessage(String message, List<String> attachments, byte[] groupId) throws EncapsulatedExceptions, GroupNotFoundException, AttachmentInvalidException, IOException, InvalidNumberException;
|
void sendGroupMessage(String message, List<String> attachments, byte[] groupId) throws EncapsulatedExceptions, GroupNotFoundException, AttachmentInvalidException, IOException;
|
||||||
|
|
||||||
String getContactName(String number) throws InvalidNumberException;
|
String getContactName(String number) throws InvalidNumberException;
|
||||||
|
|
||||||
|
|
|
@ -6,19 +6,20 @@ import net.sourceforge.argparse4j.inf.Subparser;
|
||||||
|
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
import org.asamk.signal.storage.groups.GroupInfo;
|
import org.asamk.signal.storage.groups.GroupInfo;
|
||||||
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
import org.whispersystems.util.Base64;
|
import org.whispersystems.util.Base64;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ListGroupsCommand implements LocalCommand {
|
public class ListGroupsCommand implements LocalCommand {
|
||||||
|
|
||||||
private static void printGroup(GroupInfo group, boolean detailed, String username) {
|
private static void printGroup(GroupInfo group, boolean detailed, SignalServiceAddress address) {
|
||||||
if (detailed) {
|
if (detailed) {
|
||||||
System.out.println(String.format("Id: %s Name: %s Active: %s Blocked: %b Members: %s",
|
System.out.println(String.format("Id: %s Name: %s Active: %s Blocked: %b Members: %s",
|
||||||
Base64.encodeBytes(group.groupId), group.name, group.members.contains(username), group.blocked, group.members));
|
Base64.encodeBytes(group.groupId), group.name, group.isMember(address), group.blocked, group.getMembersE164()));
|
||||||
} else {
|
} else {
|
||||||
System.out.println(String.format("Id: %s Name: %s Active: %s Blocked: %b",
|
System.out.println(String.format("Id: %s Name: %s Active: %s Blocked: %b",
|
||||||
Base64.encodeBytes(group.groupId), group.name, group.members.contains(username), group.blocked));
|
Base64.encodeBytes(group.groupId), group.name, group.isMember(address), group.blocked));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ public class ListGroupsCommand implements LocalCommand {
|
||||||
boolean detailed = ns.getBoolean("detailed");
|
boolean detailed = ns.getBoolean("detailed");
|
||||||
|
|
||||||
for (GroupInfo group : groups) {
|
for (GroupInfo group : groups) {
|
||||||
printGroup(group, detailed, m.getUsername());
|
printGroup(group, detailed, m.getSelfAddress());
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import org.asamk.signal.NotAGroupMemberException;
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
import org.asamk.signal.util.Util;
|
import org.asamk.signal.util.Util;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.EncapsulatedExceptions;
|
import org.whispersystems.signalservice.api.push.exceptions.EncapsulatedExceptions;
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -18,7 +17,6 @@ import static org.asamk.signal.util.ErrorUtils.handleEncapsulatedExceptions;
|
||||||
import static org.asamk.signal.util.ErrorUtils.handleGroupIdFormatException;
|
import static org.asamk.signal.util.ErrorUtils.handleGroupIdFormatException;
|
||||||
import static org.asamk.signal.util.ErrorUtils.handleGroupNotFoundException;
|
import static org.asamk.signal.util.ErrorUtils.handleGroupNotFoundException;
|
||||||
import static org.asamk.signal.util.ErrorUtils.handleIOException;
|
import static org.asamk.signal.util.ErrorUtils.handleIOException;
|
||||||
import static org.asamk.signal.util.ErrorUtils.handleInvalidNumberException;
|
|
||||||
import static org.asamk.signal.util.ErrorUtils.handleNotAGroupMemberException;
|
import static org.asamk.signal.util.ErrorUtils.handleNotAGroupMemberException;
|
||||||
|
|
||||||
public class QuitGroupCommand implements LocalCommand {
|
public class QuitGroupCommand implements LocalCommand {
|
||||||
|
@ -58,9 +56,6 @@ public class QuitGroupCommand implements LocalCommand {
|
||||||
} catch (GroupIdFormatException e) {
|
} catch (GroupIdFormatException e) {
|
||||||
handleGroupIdFormatException(e);
|
handleGroupIdFormatException(e);
|
||||||
return 1;
|
return 1;
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
handleInvalidNumberException(e);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,6 +171,10 @@ public class Manager implements Signal {
|
||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SignalServiceAddress getSelfAddress() {
|
||||||
|
return account.getSelfAddress();
|
||||||
|
}
|
||||||
|
|
||||||
private SignalServiceAccountManager getSignalServiceAccountManager() {
|
private SignalServiceAccountManager getSignalServiceAccountManager() {
|
||||||
return new SignalServiceAccountManager(BaseConfig.serviceConfiguration, null, account.getUsername(), account.getPassword(), account.getDeviceId(), BaseConfig.USER_AGENT, timer);
|
return new SignalServiceAccountManager(BaseConfig.serviceConfiguration, null, account.getUsername(), account.getPassword(), account.getDeviceId(), BaseConfig.USER_AGENT, timer);
|
||||||
}
|
}
|
||||||
|
@ -499,12 +503,10 @@ public class Manager implements Signal {
|
||||||
if (g == null) {
|
if (g == null) {
|
||||||
throw new GroupNotFoundException(groupId);
|
throw new GroupNotFoundException(groupId);
|
||||||
}
|
}
|
||||||
for (String member : g.members) {
|
if (!g.isMember(account.getSelfAddress())) {
|
||||||
if (member.equals(account.getUsername())) {
|
throw new NotAGroupMemberException(groupId, g.name);
|
||||||
return g;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throw new NotAGroupMemberException(groupId, g.name);
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<GroupInfo> getGroups() {
|
public List<GroupInfo> getGroups() {
|
||||||
|
@ -514,7 +516,7 @@ public class Manager implements Signal {
|
||||||
@Override
|
@Override
|
||||||
public void sendGroupMessage(String messageText, List<String> attachments,
|
public void sendGroupMessage(String messageText, List<String> attachments,
|
||||||
byte[] groupId)
|
byte[] groupId)
|
||||||
throws IOException, EncapsulatedExceptions, GroupNotFoundException, AttachmentInvalidException, InvalidNumberException {
|
throws IOException, EncapsulatedExceptions, GroupNotFoundException, AttachmentInvalidException {
|
||||||
final SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder().withBody(messageText);
|
final SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder().withBody(messageText);
|
||||||
if (attachments != null) {
|
if (attachments != null) {
|
||||||
messageBuilder.withAttachments(Utils.getSignalServiceAttachments(attachments));
|
messageBuilder.withAttachments(Utils.getSignalServiceAttachments(attachments));
|
||||||
|
@ -532,15 +534,12 @@ public class Manager implements Signal {
|
||||||
|
|
||||||
final GroupInfo g = getGroupForSending(groupId);
|
final GroupInfo g = getGroupForSending(groupId);
|
||||||
|
|
||||||
final Collection<SignalServiceAddress> membersSend = getSignalServiceAddresses(g.members);
|
sendMessageLegacy(messageBuilder, g.getMembersWithout(account.getSelfAddress()));
|
||||||
// Don't send group message to ourself
|
|
||||||
membersSend.remove(account.getSelfAddress());
|
|
||||||
sendMessageLegacy(messageBuilder, membersSend);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendGroupMessageReaction(String emoji, boolean remove, SignalServiceAddress targetAuthor,
|
public void sendGroupMessageReaction(String emoji, boolean remove, SignalServiceAddress targetAuthor,
|
||||||
long targetSentTimestamp, byte[] groupId)
|
long targetSentTimestamp, byte[] groupId)
|
||||||
throws IOException, EncapsulatedExceptions, AttachmentInvalidException, InvalidNumberException {
|
throws IOException, EncapsulatedExceptions, AttachmentInvalidException {
|
||||||
SignalServiceDataMessage.Reaction reaction = new SignalServiceDataMessage.Reaction(emoji, remove, targetAuthor, targetSentTimestamp);
|
SignalServiceDataMessage.Reaction reaction = new SignalServiceDataMessage.Reaction(emoji, remove, targetAuthor, targetSentTimestamp);
|
||||||
final SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder()
|
final SignalServiceDataMessage.Builder messageBuilder = SignalServiceDataMessage.newBuilder()
|
||||||
.withReaction(reaction)
|
.withReaction(reaction)
|
||||||
|
@ -552,13 +551,10 @@ public class Manager implements Signal {
|
||||||
messageBuilder.asGroupMessage(group);
|
messageBuilder.asGroupMessage(group);
|
||||||
}
|
}
|
||||||
final GroupInfo g = getGroupForSending(groupId);
|
final GroupInfo g = getGroupForSending(groupId);
|
||||||
final Collection<SignalServiceAddress> membersSend = getSignalServiceAddresses(g.members);
|
sendMessageLegacy(messageBuilder, g.getMembersWithout(account.getSelfAddress()));
|
||||||
// Don't send group message to ourself
|
|
||||||
membersSend.remove(account.getSelfAddress());
|
|
||||||
sendMessageLegacy(messageBuilder, membersSend);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendQuitGroupMessage(byte[] groupId) throws GroupNotFoundException, IOException, EncapsulatedExceptions, InvalidNumberException {
|
public void sendQuitGroupMessage(byte[] groupId) throws GroupNotFoundException, IOException, EncapsulatedExceptions {
|
||||||
SignalServiceGroup group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.QUIT)
|
SignalServiceGroup group = SignalServiceGroup.newBuilder(SignalServiceGroup.Type.QUIT)
|
||||||
.withId(groupId)
|
.withId(groupId)
|
||||||
.build();
|
.build();
|
||||||
|
@ -567,18 +563,18 @@ public class Manager implements Signal {
|
||||||
.asGroupMessage(group);
|
.asGroupMessage(group);
|
||||||
|
|
||||||
final GroupInfo g = getGroupForSending(groupId);
|
final GroupInfo g = getGroupForSending(groupId);
|
||||||
g.members.remove(account.getUsername());
|
g.removeMember(account.getSelfAddress());
|
||||||
account.getGroupStore().updateGroup(g);
|
account.getGroupStore().updateGroup(g);
|
||||||
|
|
||||||
sendMessageLegacy(messageBuilder, getSignalServiceAddresses(g.members));
|
sendMessageLegacy(messageBuilder, g.getMembersWithout(account.getSelfAddress()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] sendUpdateGroupMessage(byte[] groupId, String name, Collection<String> members, String avatarFile) throws IOException, EncapsulatedExceptions, GroupNotFoundException, AttachmentInvalidException, InvalidNumberException {
|
private byte[] sendUpdateGroupMessage(byte[] groupId, String name, Collection<SignalServiceAddress> members, String avatarFile) throws IOException, EncapsulatedExceptions, GroupNotFoundException, AttachmentInvalidException {
|
||||||
GroupInfo g;
|
GroupInfo g;
|
||||||
if (groupId == null) {
|
if (groupId == null) {
|
||||||
// Create new group
|
// Create new group
|
||||||
g = new GroupInfo(KeyUtils.createGroupId());
|
g = new GroupInfo(KeyUtils.createGroupId());
|
||||||
g.members.add(account.getUsername());
|
g.addMembers(Collections.singleton(account.getSelfAddress()));
|
||||||
} else {
|
} else {
|
||||||
g = getGroupForSending(groupId);
|
g = getGroupForSending(groupId);
|
||||||
}
|
}
|
||||||
|
@ -588,25 +584,26 @@ public class Manager implements Signal {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (members != null) {
|
if (members != null) {
|
||||||
Set<String> newMembers = new HashSet<>();
|
final Set<String> newE164Members = new HashSet<>();
|
||||||
for (String member : members) {
|
for (SignalServiceAddress member : members) {
|
||||||
member = Utils.canonicalizeNumber(member, account.getUsername());
|
if (g.isMember(member) || !member.getNumber().isPresent()) {
|
||||||
if (g.members.contains(member)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
newMembers.add(member);
|
newE164Members.add(member.getNumber().get());
|
||||||
g.members.add(member);
|
|
||||||
}
|
}
|
||||||
final List<ContactTokenDetails> contacts = accountManager.getContacts(newMembers);
|
|
||||||
if (contacts.size() != newMembers.size()) {
|
final List<ContactTokenDetails> contacts = accountManager.getContacts(newE164Members);
|
||||||
|
if (contacts.size() != newE164Members.size()) {
|
||||||
// Some of the new members are not registered on Signal
|
// Some of the new members are not registered on Signal
|
||||||
for (ContactTokenDetails contact : contacts) {
|
for (ContactTokenDetails contact : contacts) {
|
||||||
newMembers.remove(contact.getNumber());
|
newE164Members.remove(contact.getNumber());
|
||||||
}
|
}
|
||||||
System.err.println("Failed to add members " + Util.join(", ", newMembers) + " to group: Not registered on Signal");
|
System.err.println("Failed to add members " + Util.join(", ", newE164Members) + " to group: Not registered on Signal");
|
||||||
System.err.println("Aborting…");
|
System.err.println("Aborting…");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g.addMembers(members);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avatarFile != null) {
|
if (avatarFile != null) {
|
||||||
|
@ -619,10 +616,7 @@ public class Manager implements Signal {
|
||||||
|
|
||||||
SignalServiceDataMessage.Builder messageBuilder = getGroupUpdateMessageBuilder(g);
|
SignalServiceDataMessage.Builder messageBuilder = getGroupUpdateMessageBuilder(g);
|
||||||
|
|
||||||
final Collection<SignalServiceAddress> membersSend = getSignalServiceAddresses(g.members);
|
sendMessageLegacy(messageBuilder, g.getMembersWithout(account.getSelfAddress()));
|
||||||
// Don't send group message to ourself
|
|
||||||
membersSend.remove(account.getSelfAddress());
|
|
||||||
sendMessageLegacy(messageBuilder, membersSend);
|
|
||||||
return g.groupId;
|
return g.groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,7 +626,7 @@ public class Manager implements Signal {
|
||||||
}
|
}
|
||||||
GroupInfo g = getGroupForSending(groupId);
|
GroupInfo g = getGroupForSending(groupId);
|
||||||
|
|
||||||
if (!g.members.contains(recipient.getNumber().get())) {
|
if (!g.isMember(recipient)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -819,9 +813,9 @@ public class Manager implements Signal {
|
||||||
public List<String> getGroupMembers(byte[] groupId) {
|
public List<String> getGroupMembers(byte[] groupId) {
|
||||||
GroupInfo group = getGroup(groupId);
|
GroupInfo group = getGroup(groupId);
|
||||||
if (group == null) {
|
if (group == null) {
|
||||||
return new ArrayList<>();
|
return Collections.emptyList();
|
||||||
} else {
|
} else {
|
||||||
return new ArrayList<>(group.members);
|
return new ArrayList<>(group.getMembersE164());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,7 +833,7 @@ public class Manager implements Signal {
|
||||||
if (avatar.isEmpty()) {
|
if (avatar.isEmpty()) {
|
||||||
avatar = null;
|
avatar = null;
|
||||||
}
|
}
|
||||||
return sendUpdateGroupMessage(groupId, name, members, avatar);
|
return sendUpdateGroupMessage(groupId, name, members == null ? null : getSignalServiceAddresses(members), avatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1284,7 +1278,7 @@ public class Manager implements Signal {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
group.members.remove(source.getNumber().get());
|
group.removeMember(source);
|
||||||
account.getGroupStore().updateGroup(group);
|
account.getGroupStore().updateGroup(group);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1559,10 +1553,10 @@ public class Manager implements Signal {
|
||||||
}
|
}
|
||||||
syncGroup.addMembers(g.getMembers());
|
syncGroup.addMembers(g.getMembers());
|
||||||
if (!g.isActive()) {
|
if (!g.isActive()) {
|
||||||
syncGroup.members.remove(account.getUsername());
|
syncGroup.removeMember(account.getSelfAddress());
|
||||||
} else {
|
} else {
|
||||||
// Add ourself to the member set as it's marked as active
|
// Add ourself to the member set as it's marked as active
|
||||||
syncGroup.members.add(account.getUsername());
|
syncGroup.addMembers(Collections.singleton(account.getSelfAddress()));
|
||||||
}
|
}
|
||||||
syncGroup.blocked = g.isBlocked();
|
syncGroup.blocked = g.isBlocked();
|
||||||
if (g.getColor().isPresent()) {
|
if (g.getColor().isPresent()) {
|
||||||
|
@ -1778,7 +1772,7 @@ public class Manager implements Signal {
|
||||||
ThreadInfo info = account.getThreadStore().getThread(Base64.encodeBytes(record.groupId));
|
ThreadInfo info = account.getThreadStore().getThread(Base64.encodeBytes(record.groupId));
|
||||||
out.write(new DeviceGroup(record.groupId, Optional.fromNullable(record.name),
|
out.write(new DeviceGroup(record.groupId, Optional.fromNullable(record.name),
|
||||||
new ArrayList<>(record.getMembers()), createGroupAvatarAttachment(record.groupId),
|
new ArrayList<>(record.getMembers()), createGroupAvatarAttachment(record.groupId),
|
||||||
record.members.contains(account.getUsername()), Optional.fromNullable(info != null ? info.messageExpirationTime : null),
|
record.isMember(account.getSelfAddress()), Optional.fromNullable(info != null ? info.messageExpirationTime : null),
|
||||||
Optional.fromNullable(record.color), record.blocked, Optional.fromNullable(record.inboxPosition), record.archived));
|
Optional.fromNullable(record.color), record.blocked, Optional.fromNullable(record.inboxPosition), record.archived));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,15 +2,29 @@ package org.asamk.signal.storage.groups;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class GroupInfo {
|
public class GroupInfo {
|
||||||
|
|
||||||
|
private static final ObjectMapper jsonProcessor = new ObjectMapper();
|
||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
public final byte[] groupId;
|
public final byte[] groupId;
|
||||||
|
|
||||||
|
@ -18,7 +32,9 @@ public class GroupInfo {
|
||||||
public String name;
|
public String name;
|
||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
public Set<String> members = new HashSet<>();
|
@JsonDeserialize(using = MembersDeserializer.class)
|
||||||
|
@JsonSerialize(using = MembersSerializer.class)
|
||||||
|
public Set<SignalServiceAddress> members = new HashSet<>();
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
public String color;
|
public String color;
|
||||||
@JsonProperty(defaultValue = "false")
|
@JsonProperty(defaultValue = "false")
|
||||||
|
@ -38,7 +54,7 @@ public class GroupInfo {
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GroupInfo(@JsonProperty("groupId") byte[] groupId, @JsonProperty("name") String name, @JsonProperty("members") Collection<String> members, @JsonProperty("avatarId") long avatarId, @JsonProperty("color") String color, @JsonProperty("blocked") boolean blocked, @JsonProperty("inboxPosition") Integer inboxPosition, @JsonProperty("archived") boolean archived) {
|
public GroupInfo(@JsonProperty("groupId") byte[] groupId, @JsonProperty("name") String name, @JsonProperty("members") Collection<SignalServiceAddress> members, @JsonProperty("avatarId") long avatarId, @JsonProperty("color") String color, @JsonProperty("blocked") boolean blocked, @JsonProperty("inboxPosition") Integer inboxPosition, @JsonProperty("archived") boolean archived) {
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.members.addAll(members);
|
this.members.addAll(members);
|
||||||
|
@ -56,16 +72,108 @@ public class GroupInfo {
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public Set<SignalServiceAddress> getMembers() {
|
public Set<SignalServiceAddress> getMembers() {
|
||||||
Set<SignalServiceAddress> addresses = new HashSet<>(members.size());
|
return members;
|
||||||
for (String member : members) {
|
|
||||||
addresses.add(new SignalServiceAddress(null, member));
|
|
||||||
}
|
|
||||||
return addresses;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMembers(Collection<SignalServiceAddress> members) {
|
@JsonIgnore
|
||||||
|
public Set<String> getMembersE164() {
|
||||||
|
Set<String> membersE164 = new HashSet<>();
|
||||||
for (SignalServiceAddress member : members) {
|
for (SignalServiceAddress member : members) {
|
||||||
this.members.add(member.getNumber().get());
|
if (!member.getNumber().isPresent()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
membersE164.add(member.getNumber().get());
|
||||||
|
}
|
||||||
|
return membersE164;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public Set<SignalServiceAddress> getMembersWithout(SignalServiceAddress address) {
|
||||||
|
Set<SignalServiceAddress> members = new HashSet<>(this.members.size());
|
||||||
|
for (SignalServiceAddress member : this.members) {
|
||||||
|
if (!member.matches(address)) {
|
||||||
|
members.add(member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return members;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMembers(Collection<SignalServiceAddress> addresses) {
|
||||||
|
for (SignalServiceAddress address : addresses) {
|
||||||
|
removeMember(address);
|
||||||
|
this.members.add(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeMember(SignalServiceAddress address) {
|
||||||
|
this.members.removeIf(member -> member.matches(address));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public boolean isMember(SignalServiceAddress address) {
|
||||||
|
for (SignalServiceAddress member : this.members) {
|
||||||
|
if (member.matches(address)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class JsonSignalServiceAddress {
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private UUID uuid;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private String number;
|
||||||
|
|
||||||
|
JsonSignalServiceAddress(@JsonProperty("uuid") final UUID uuid, @JsonProperty("number") final String number) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.number = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonSignalServiceAddress(SignalServiceAddress address) {
|
||||||
|
this.uuid = address.getUuid().orNull();
|
||||||
|
this.number = address.getNumber().orNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
SignalServiceAddress toSignalServiceAddress() {
|
||||||
|
return new SignalServiceAddress(uuid, number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MembersSerializer extends JsonSerializer<Set<SignalServiceAddress>> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(final Set<SignalServiceAddress> value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException {
|
||||||
|
jgen.writeStartArray(value.size());
|
||||||
|
for (SignalServiceAddress address : value) {
|
||||||
|
if (address.getUuid().isPresent()) {
|
||||||
|
jgen.writeObject(new JsonSignalServiceAddress(address));
|
||||||
|
} else {
|
||||||
|
jgen.writeString(address.getNumber().get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jgen.writeEndArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MembersDeserializer extends JsonDeserializer<Set<SignalServiceAddress>> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<SignalServiceAddress> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
|
||||||
|
Set<SignalServiceAddress> addresses = new HashSet<>();
|
||||||
|
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
|
||||||
|
for (JsonNode n : node) {
|
||||||
|
if (n.isTextual()) {
|
||||||
|
addresses.add(new SignalServiceAddress(null, n.textValue()));
|
||||||
|
} else {
|
||||||
|
JsonSignalServiceAddress address = jsonProcessor.treeToValue(n, JsonSignalServiceAddress.class);
|
||||||
|
addresses.add(address.toSignalServiceAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return addresses;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue