mirror of
https://github.com/AsamK/signal-cli
synced 2025-09-03 20:50:38 +00:00
DBus sendTyping and getGroupsByName
flesh out sendTyping method to include multiple recipients new getGroupsByName to lookup groupId when you know the group name update documentation
This commit is contained in:
parent
f5089789fb
commit
cc738e55b5
7 changed files with 224 additions and 58 deletions
|
@ -106,6 +106,7 @@ Exceptions: None
|
||||||
=== Group control methods
|
=== Group control methods
|
||||||
The following methods listen to the recipient's object path, which is constructed as follows:
|
The following methods listen to the recipient's object path, which is constructed as follows:
|
||||||
"/org/asamk/Signal/" + DBusNumber
|
"/org/asamk/Signal/" + DBusNumber
|
||||||
|
|
||||||
* DBusNumber : recipient's phone number, with underscore (_) replacing plus (+)
|
* DBusNumber : recipient's phone number, with underscore (_) replacing plus (+)
|
||||||
|
|
||||||
createGroup(groupName<s>, members<as>, avatar<s>) -> groupId<ay>::
|
createGroup(groupName<s>, members<as>, avatar<s>) -> groupId<ay>::
|
||||||
|
@ -114,17 +115,28 @@ createGroup(groupName<s>, members<as>, avatar<s>) -> groupId<ay>::
|
||||||
* avatar : Filename of avatar picture to be set for group (empty if none)
|
* avatar : Filename of avatar picture to be set for group (empty if none)
|
||||||
* groupId : Byte array representing the internal group identifier
|
* groupId : Byte array representing the internal group identifier
|
||||||
|
|
||||||
Exceptions: AttachmentInvalid, Failure, InvalidNumber;
|
Exceptions: AttachmentInvalid, Failure, InvalidNumber
|
||||||
|
|
||||||
getGroup(groupId<ay>) -> objectPath<o>::
|
getGroup(groupId<ay>) -> groupPath<o>::
|
||||||
* groupId : Byte array representing the internal group identifier
|
|
||||||
* objectPath : DBusPath for the group
|
|
||||||
|
|
||||||
getGroupMembers(groupId<ay>) -> members<as>::
|
|
||||||
* groupId : Byte array representing the internal group identifier
|
* groupId : Byte array representing the internal group identifier
|
||||||
* members : String array with the phone numbers of all active members of a group
|
* groupPath : DBusPath for the group
|
||||||
|
|
||||||
Exceptions: None, if the group name is not found an empty array is returned
|
Exceptions: GroupNotFound
|
||||||
|
|
||||||
|
getGroups() -> groupPaths<o>::
|
||||||
|
* groupPaths : DBusPaths for the groups
|
||||||
|
|
||||||
|
All groups known are returned, regardless of their active or blocked status.
|
||||||
|
|
||||||
|
Exceptions: None
|
||||||
|
|
||||||
|
getGroupsByName(groupName<s>) -> groupIds<aay>::
|
||||||
|
* groupName : String representing the display name of the group
|
||||||
|
* groupIds : Array of Byte arrays representing the internal group identifiers
|
||||||
|
|
||||||
|
Returns empty array if no groups match the groupName.
|
||||||
|
|
||||||
|
Exceptions: None
|
||||||
|
|
||||||
joinGroup(inviteURI<s>) -> <>::
|
joinGroup(inviteURI<s>) -> <>::
|
||||||
* inviteURI : String starting with https://signal.group/#
|
* inviteURI : String starting with https://signal.group/#
|
||||||
|
@ -134,8 +146,8 @@ Behavior of this method depends on the `requirePermission` parameter of the `ena
|
||||||
Exceptions: Failure
|
Exceptions: Failure
|
||||||
|
|
||||||
listGroups() -> groups<a(oays)>::
|
listGroups() -> groups<a(oays)>::
|
||||||
* groups : Array of Structs(objectPath, groupId, groupName)
|
* groups : Array of Structs(groupPath, groupId, groupName)
|
||||||
** objectPath : DBusPath
|
** groupPath : DBusPath for the group
|
||||||
** groupId : Byte array representing the internal group identifier
|
** groupId : Byte array representing the internal group identifier
|
||||||
** groupName : String representing the display name of the group
|
** groupName : String representing the display name of the group
|
||||||
|
|
||||||
|
@ -167,10 +179,12 @@ Exceptions: Failure, GroupNotFound, InvalidGroupId
|
||||||
=== Group methods
|
=== Group methods
|
||||||
The following methods listen to the group's object path, which can be obtained from the listGroups() method and is constructed as follows:
|
The following methods listen to the group's object path, which can be obtained from the listGroups() method and is constructed as follows:
|
||||||
"/org/asamk/Signal/" + DBusNumber + "/Groups/" + DBusGroupId
|
"/org/asamk/Signal/" + DBusNumber + "/Groups/" + DBusGroupId
|
||||||
|
|
||||||
* DBusNumber : recipient's phone number, with underscore (_) replacing plus (+)
|
* DBusNumber : recipient's phone number, with underscore (_) replacing plus (+)
|
||||||
* DBusGroupId : groupId in base64 format, with underscore (_) replacing plus (+), equals (=), or slash (/)
|
* DBusGroupId : groupId in base64 format, with underscore (_) replacing plus (+), equals (=), or slash (/)
|
||||||
|
|
||||||
Groups have the following (case-sensitive) properties:
|
Groups have the following (case-sensitive) properties:
|
||||||
|
|
||||||
* Id<ay> (read-only) : Byte array representing the internal group identifier
|
* Id<ay> (read-only) : Byte array representing the internal group identifier
|
||||||
* Name<s> : Display name of the group
|
* Name<s> : Display name of the group
|
||||||
* Description<s> : Description of the group
|
* Description<s> : Description of the group
|
||||||
|
@ -253,19 +267,32 @@ Exceptions: Failure
|
||||||
=== Deprecated group control methods
|
=== Deprecated group control methods
|
||||||
The following deprecated methods listen to the recipient's object path, which is constructed as follows:
|
The following deprecated methods listen to the recipient's object path, which is constructed as follows:
|
||||||
"/org/asamk/Signal/" + DBusNumber
|
"/org/asamk/Signal/" + DBusNumber
|
||||||
|
|
||||||
* DBusNumber : recipient's phone number, with underscore (_) replacing plus (+)
|
* DBusNumber : recipient's phone number, with underscore (_) replacing plus (+)
|
||||||
|
|
||||||
getGroupIds() -> groupList<aay>::
|
getGroupIds() -> groupIds<aay>::
|
||||||
groupList : Array of Byte arrays representing the internal group identifiers
|
* groupIds : Array of Byte arrays representing the internal group identifiers
|
||||||
|
|
||||||
All groups known are returned, regardless of their active or blocked status. To query that use isMember() and isGroupBlocked()
|
All groups known are returned, regardless of their active or blocked status.
|
||||||
|
|
||||||
|
Replacement: Use the `getGroups()` method.
|
||||||
|
|
||||||
Exceptions: None
|
Exceptions: None
|
||||||
|
|
||||||
|
getGroupMembers(groupId<ay>) -> members<as>::
|
||||||
|
* groupId : Byte array representing the internal group identifier
|
||||||
|
* members : String array with the phone numbers of all active members of a group
|
||||||
|
|
||||||
|
Replacement: Use the `Members` property.
|
||||||
|
|
||||||
|
Exceptions: None, if the group name is not found an empty array is returned
|
||||||
|
|
||||||
getGroupName(groupId<ay>) -> groupName<s>::
|
getGroupName(groupId<ay>) -> groupName<s>::
|
||||||
* groupId : Byte array representing the internal group identifier
|
* groupId : Byte array representing the internal group identifier
|
||||||
* groupName : The display name of the group
|
* groupName : The display name of the group
|
||||||
|
|
||||||
|
Replacement: Use the `Name` property.
|
||||||
|
|
||||||
Exceptions: None, if the group name is not found an empty string is returned
|
Exceptions: None, if the group name is not found an empty string is returned
|
||||||
|
|
||||||
isGroupBlocked(groupId<ay>) -> isGroupBlocked<b>::
|
isGroupBlocked(groupId<ay>) -> isGroupBlocked<b>::
|
||||||
|
@ -274,6 +301,8 @@ isGroupBlocked(groupId<ay>) -> isGroupBlocked<b>::
|
||||||
|
|
||||||
Dbus will not forward messages from a group when you have blocked it.
|
Dbus will not forward messages from a group when you have blocked it.
|
||||||
|
|
||||||
|
Replacement: Use the `IsBlocked` property.
|
||||||
|
|
||||||
Exceptions: InvalidGroupId, Failure
|
Exceptions: InvalidGroupId, Failure
|
||||||
|
|
||||||
isMember(groupId<ay>) -> isMember<b>::
|
isMember(groupId<ay>) -> isMember<b>::
|
||||||
|
@ -282,11 +311,17 @@ isMember(groupId<ay>) -> isMember<b>::
|
||||||
|
|
||||||
Note that this method does not raise an Exception for a non-existing/unknown group but will simply return 0 (false)
|
Note that this method does not raise an Exception for a non-existing/unknown group but will simply return 0 (false)
|
||||||
|
|
||||||
|
Replacement: Use the `IsMember` property.
|
||||||
|
|
||||||
|
Exceptions: None
|
||||||
|
|
||||||
quitGroup(groupId<ay>) -> <>::
|
quitGroup(groupId<ay>) -> <>::
|
||||||
* groupId : Byte array representing the internal group identifier
|
* groupId : Byte array representing the internal group identifier
|
||||||
|
|
||||||
Note that quitting a group will not remove the group from the getGroupIds command, but set it inactive which can be tested with isMember()
|
Note that quitting a group will not remove the group from the getGroupIds command, but set it inactive which can be tested with isMember()
|
||||||
|
|
||||||
|
Replacement: Use the `quitGroup()` group method.
|
||||||
|
|
||||||
Exceptions: GroupNotFound, Failure, InvalidGroupId
|
Exceptions: GroupNotFound, Failure, InvalidGroupId
|
||||||
|
|
||||||
setGroupBlocked(groupId<ay>, block<b>) -> <>::
|
setGroupBlocked(groupId<ay>, block<b>) -> <>::
|
||||||
|
@ -295,6 +330,8 @@ setGroupBlocked(groupId<ay>, block<b>) -> <>::
|
||||||
|
|
||||||
Messages from blocked groups will no longer be forwarded via DBus.
|
Messages from blocked groups will no longer be forwarded via DBus.
|
||||||
|
|
||||||
|
Replacement: Use the `IsBlocked` property.
|
||||||
|
|
||||||
Exceptions: GroupNotFound, InvalidGroupId
|
Exceptions: GroupNotFound, InvalidGroupId
|
||||||
|
|
||||||
updateGroup(groupId<ay>, newName<s>, members<as>, avatar<s>) -> groupId<ay>::
|
updateGroup(groupId<ay>, newName<s>, members<as>, avatar<s>) -> groupId<ay>::
|
||||||
|
@ -303,11 +340,19 @@ updateGroup(groupId<ay>, newName<s>, members<as>, avatar<s>) -> groupId<ay>::
|
||||||
* members : String array of new members to be invited to group
|
* members : String array of new members to be invited to group
|
||||||
* avatar : Filename of avatar picture to be set for group (empty if none)
|
* avatar : Filename of avatar picture to be set for group (empty if none)
|
||||||
|
|
||||||
|
To create a new group, send an empty groupId and the newName. The return value
|
||||||
|
will be the groupId randomly assigned to the new group.
|
||||||
|
|
||||||
|
Replacement: To create a group, use the `createGroup()` group method. To
|
||||||
|
update the name, members, or avatar, use the respective property (`Name`,
|
||||||
|
`Members`, `Avatar`).
|
||||||
|
|
||||||
Exceptions: AttachmentInvalid, Failure, InvalidNumber, GroupNotFound
|
Exceptions: AttachmentInvalid, Failure, InvalidNumber, GroupNotFound
|
||||||
|
|
||||||
=== Device control methods
|
=== Device control methods
|
||||||
The following methods listen to the recipient's object path, which is constructed as follows:
|
The following methods listen to the recipient's object path, which is constructed as follows:
|
||||||
"/org/asamk/Signal/" + DBusNumber
|
"/org/asamk/Signal/" + DBusNumber
|
||||||
|
|
||||||
* DBusNumber : recipient's phone number, with underscore (_) replacing plus (+)
|
* DBusNumber : recipient's phone number, with underscore (_) replacing plus (+)
|
||||||
|
|
||||||
addDevice(deviceUri<s>) -> <>::
|
addDevice(deviceUri<s>) -> <>::
|
||||||
|
@ -315,13 +360,13 @@ addDevice(deviceUri<s>) -> <>::
|
||||||
|
|
||||||
getDevice(deviceId<x>) -> devicePath<o>::
|
getDevice(deviceId<x>) -> devicePath<o>::
|
||||||
* deviceId : Long representing a deviceId
|
* deviceId : Long representing a deviceId
|
||||||
* devicePath : DBusPath object for the device
|
* devicePath : DBusPath for the device
|
||||||
|
|
||||||
Exceptions: DeviceNotFound
|
Exceptions: DeviceNotFound
|
||||||
|
|
||||||
listDevices() -> devices<a(oxs)>::
|
listDevices() -> devices<a(oxs)>::
|
||||||
* devices : Array of structs (objectPath, id, name)
|
* devices : Array of structs (devicePath, id, name)
|
||||||
** objectPath : DBusPath representing the device's object path
|
** devicePath : DBusPath representing the device
|
||||||
** id : Long representing the deviceId
|
** id : Long representing the deviceId
|
||||||
** name : String representing the device's name
|
** name : String representing the device's name
|
||||||
|
|
||||||
|
@ -342,10 +387,12 @@ Exceptions: Failure
|
||||||
=== Device methods and properties
|
=== Device methods and properties
|
||||||
The following methods listen to the device's object path, which is constructed as follows:
|
The following methods listen to the device's object path, which is constructed as follows:
|
||||||
"/org/asamk/Signal/" + DBusNumber + "/Devices/" + deviceId
|
"/org/asamk/Signal/" + DBusNumber + "/Devices/" + deviceId
|
||||||
|
|
||||||
* DBusNumber : recipient's phone number, with underscore (_) replacing plus (+)
|
* DBusNumber : recipient's phone number, with underscore (_) replacing plus (+)
|
||||||
* deviceId : Long representing the device identifier (obtained from listDevices() method)
|
* deviceId : Long representing the device identifier (obtained from listDevices() method)
|
||||||
|
|
||||||
Devices have the following (case-sensitive) properties:
|
Devices have the following (case-sensitive) properties:
|
||||||
|
|
||||||
* Id<x> (read-only) : Long representing the device identifier
|
* Id<x> (read-only) : Long representing the device identifier
|
||||||
* Created<x> (read-only) : Long representing the number of milliseconds since the Unix epoch
|
* Created<x> (read-only) : Long representing the number of milliseconds since the Unix epoch
|
||||||
* LastSeen<x> (read-only) : Long representing the number of milliseconds since the Unix epoch
|
* LastSeen<x> (read-only) : Long representing the number of milliseconds since the Unix epoch
|
||||||
|
@ -473,11 +520,23 @@ Depending on the type of the recipient(s) field this deletes a message with one
|
||||||
|
|
||||||
Exceptions: Failure, InvalidNumber
|
Exceptions: Failure, InvalidNumber
|
||||||
|
|
||||||
sendTyping(recipient<s>, stop<b>) -> <>::
|
sendTyping(number<s>, stop<b>) -> <>::
|
||||||
* recipient : Phone number of a single recipient
|
* number : Phone number of a single recipient
|
||||||
* targetSentTimestamp : True, if typing state should be stopped
|
* stop : true = stop typing, false = start typing
|
||||||
|
|
||||||
Exceptions: Failure, GroupNotFound, UntrustedIdentity
|
Stop or start sending typing indicators to a single recipient.
|
||||||
|
|
||||||
|
Exceptions: Failure, UntrustedIdentity
|
||||||
|
|
||||||
|
sendTyping(stop<b>, groupIdStrings<as>, numbers<as>) -> <>::
|
||||||
|
* stop : true = stop typing, false = start typing
|
||||||
|
* groupIdStrings : List of strings representing groupIds in base64-encoded format for the groups
|
||||||
|
* numbers : List of phone numbers for recipients
|
||||||
|
|
||||||
|
Stop or start sending typing indicators to a list of recipients and/or a list of groups. The groupIdString is
|
||||||
|
derived from the groupId byte array by encoding it in base64 form.
|
||||||
|
|
||||||
|
Exceptions: Failure, GroupNotFound, UntrustedIdentity;
|
||||||
|
|
||||||
setContactBlocked(number<s>, block<b>) -> <>::
|
setContactBlocked(number<s>, block<b>) -> <>::
|
||||||
* number : Phone number affected by method
|
* number : Phone number affected by method
|
||||||
|
|
|
@ -31,8 +31,14 @@ public interface Signal extends DBusInterface {
|
||||||
|
|
||||||
void sendTyping(
|
void sendTyping(
|
||||||
String recipient, boolean stop
|
String recipient, boolean stop
|
||||||
|
) throws Error.Failure, Error.UntrustedIdentity;
|
||||||
|
|
||||||
|
void sendTyping(
|
||||||
|
boolean stop, List<String> groupIdStrings, List<String> numbers
|
||||||
) throws Error.Failure, Error.GroupNotFound, Error.UntrustedIdentity;
|
) throws Error.Failure, Error.GroupNotFound, Error.UntrustedIdentity;
|
||||||
|
|
||||||
|
List<byte[]> getGroupsByName(String groupName);
|
||||||
|
|
||||||
void sendReadReceipt(
|
void sendReadReceipt(
|
||||||
String recipient, List<Long> messageIds
|
String recipient, List<Long> messageIds
|
||||||
) throws Error.Failure, Error.UntrustedIdentity;
|
) throws Error.Failure, Error.UntrustedIdentity;
|
||||||
|
|
|
@ -24,6 +24,7 @@ public interface SignalControl extends DBusInterface {
|
||||||
|
|
||||||
void verifyWithPin(String number, String verificationCode, String pin) throws Error.Failure, Error.InvalidNumber;
|
void verifyWithPin(String number, String verificationCode, String pin) throws Error.Failure, Error.InvalidNumber;
|
||||||
|
|
||||||
|
String link() throws Error.Failure;
|
||||||
String link(String newDeviceName) throws Error.Failure;
|
String link(String newDeviceName) throws Error.Failure;
|
||||||
|
|
||||||
public String version();
|
public String version();
|
||||||
|
|
|
@ -2,6 +2,7 @@ package org.asamk.signal.dbus;
|
||||||
|
|
||||||
import org.asamk.Signal;
|
import org.asamk.Signal;
|
||||||
import org.asamk.signal.DbusConfig;
|
import org.asamk.signal.DbusConfig;
|
||||||
|
import org.asamk.signal.commands.exceptions.UserErrorException;
|
||||||
import org.asamk.signal.manager.AttachmentInvalidException;
|
import org.asamk.signal.manager.AttachmentInvalidException;
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
import org.asamk.signal.manager.NotMasterDeviceException;
|
import org.asamk.signal.manager.NotMasterDeviceException;
|
||||||
|
@ -298,14 +299,17 @@ public class DbusManagerImpl implements Manager {
|
||||||
public void sendTypingMessage(
|
public void sendTypingMessage(
|
||||||
final TypingAction action, final Set<RecipientIdentifier> recipients
|
final TypingAction action, final Set<RecipientIdentifier> recipients
|
||||||
) throws IOException, UntrustedIdentityException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
|
) throws IOException, UntrustedIdentityException, NotAGroupMemberException, GroupNotFoundException, GroupSendingNotAllowedException {
|
||||||
|
List<String> numbers = new ArrayList<>();
|
||||||
|
List<String> groupIdStrings = new ArrayList<>();
|
||||||
|
boolean typingAction = (action == TypingAction.START);
|
||||||
for (final var recipient : recipients) {
|
for (final var recipient : recipients) {
|
||||||
if (recipient instanceof RecipientIdentifier.Single) {
|
if (recipient instanceof RecipientIdentifier.Single) {
|
||||||
signal.sendTyping(((RecipientIdentifier.Single) recipient).getIdentifier(),
|
numbers.add(((RecipientIdentifier.Single) recipient).getIdentifier());
|
||||||
action == TypingAction.STOP);
|
|
||||||
} else if (recipient instanceof RecipientIdentifier.Group) {
|
} else if (recipient instanceof RecipientIdentifier.Group) {
|
||||||
throw new UnsupportedOperationException();
|
groupIdStrings.add(((RecipientIdentifier.Group) recipient).groupId.toBase64());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
signal.sendTyping(typingAction, groupIdStrings, numbers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -131,6 +131,11 @@ public class DbusSignalControlImpl implements org.asamk.SignalControl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String link() throws Error.Failure {
|
||||||
|
return link("cli");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String link(final String newDeviceName) throws Error.Failure {
|
public String link(final String newDeviceName) throws Error.Failure {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.asamk.signal.manager.Manager;
|
||||||
import org.asamk.signal.manager.NotMasterDeviceException;
|
import org.asamk.signal.manager.NotMasterDeviceException;
|
||||||
import org.asamk.signal.manager.StickerPackInvalidException;
|
import org.asamk.signal.manager.StickerPackInvalidException;
|
||||||
import org.asamk.signal.manager.UntrustedIdentityException;
|
import org.asamk.signal.manager.UntrustedIdentityException;
|
||||||
|
import org.asamk.signal.manager.api.Group;
|
||||||
import org.asamk.signal.manager.api.Identity;
|
import org.asamk.signal.manager.api.Identity;
|
||||||
import org.asamk.signal.manager.api.Message;
|
import org.asamk.signal.manager.api.Message;
|
||||||
import org.asamk.signal.manager.api.RecipientIdentifier;
|
import org.asamk.signal.manager.api.RecipientIdentifier;
|
||||||
|
@ -23,7 +24,9 @@ import org.asamk.signal.manager.groups.LastGroupAdminException;
|
||||||
import org.asamk.signal.manager.groups.NotAGroupMemberException;
|
import org.asamk.signal.manager.groups.NotAGroupMemberException;
|
||||||
import org.asamk.signal.manager.storage.recipients.Profile;
|
import org.asamk.signal.manager.storage.recipients.Profile;
|
||||||
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
||||||
|
import org.asamk.signal.util.CommandUtil;
|
||||||
import org.asamk.signal.util.ErrorUtils;
|
import org.asamk.signal.util.ErrorUtils;
|
||||||
|
|
||||||
import org.freedesktop.dbus.DBusPath;
|
import org.freedesktop.dbus.DBusPath;
|
||||||
import org.freedesktop.dbus.connections.impl.DBusConnection;
|
import org.freedesktop.dbus.connections.impl.DBusConnection;
|
||||||
import org.freedesktop.dbus.exceptions.DBusException;
|
import org.freedesktop.dbus.exceptions.DBusException;
|
||||||
|
@ -191,6 +194,25 @@ public class DbusSignalImpl implements Signal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<byte[]> getGroupsByName(String groupName) {
|
||||||
|
List<byte[]>groupList = new ArrayList<>();
|
||||||
|
List<byte[]>result = new ArrayList<>();
|
||||||
|
groupList = getGroupIds();
|
||||||
|
org.asamk.signal.manager.api.Group group = null;
|
||||||
|
for (byte[] groupId : groupList) {
|
||||||
|
try {
|
||||||
|
group = m.getGroup(getGroupId(groupId));
|
||||||
|
} catch (AssertionError e) {
|
||||||
|
throw new Error.Failure(e.getMessage());
|
||||||
|
}
|
||||||
|
if (group.getTitle().equals(groupName)) {
|
||||||
|
result.add(groupId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long sendGroupRemoteDeleteMessage(
|
public long sendGroupRemoteDeleteMessage(
|
||||||
final long targetSentTimestamp, final byte[] groupId
|
final long targetSentTimestamp, final byte[] groupId
|
||||||
|
@ -245,26 +267,6 @@ public class DbusSignalImpl implements Signal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendTyping(
|
|
||||||
final String recipient, final boolean stop
|
|
||||||
) throws Error.Failure, Error.GroupNotFound, Error.UntrustedIdentity {
|
|
||||||
try {
|
|
||||||
var recipients = new ArrayList<String>(1);
|
|
||||||
recipients.add(recipient);
|
|
||||||
m.sendTypingMessage(stop ? TypingAction.STOP : TypingAction.START,
|
|
||||||
getSingleRecipientIdentifiers(recipients, m.getSelfNumber()).stream()
|
|
||||||
.map(RecipientIdentifier.class::cast)
|
|
||||||
.collect(Collectors.toSet()));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new Error.Failure(e.getMessage());
|
|
||||||
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
|
|
||||||
throw new Error.GroupNotFound(e.getMessage());
|
|
||||||
} catch (UntrustedIdentityException e) {
|
|
||||||
throw new Error.UntrustedIdentity(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendReadReceipt(
|
public void sendReadReceipt(
|
||||||
final String recipient, final List<Long> messageIds
|
final String recipient, final List<Long> messageIds
|
||||||
|
@ -363,6 +365,44 @@ public class DbusSignalImpl implements Signal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendTyping(String recipient, boolean stop) {
|
||||||
|
List<String> numbers = Arrays.asList(recipient);
|
||||||
|
List<String> groupIdStrings = Arrays.asList();
|
||||||
|
sendTyping(stop, null, numbers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendTyping(boolean stop, List<String> groupIdStrings, List<String> numbers) {
|
||||||
|
final boolean noNumbers = numbers == null || numbers.isEmpty();
|
||||||
|
final boolean noGroup = groupIdStrings == null || groupIdStrings.isEmpty();
|
||||||
|
if (noNumbers && noGroup) {
|
||||||
|
throw new Error.Failure("No recipients given");
|
||||||
|
}
|
||||||
|
|
||||||
|
final TypingAction action = stop ? TypingAction.STOP : TypingAction.START;
|
||||||
|
final var timestamp = System.currentTimeMillis();
|
||||||
|
final var localNumber = m.getSelfNumber();
|
||||||
|
Set<RecipientIdentifier> recipients = new HashSet<RecipientIdentifier>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!noGroup) {
|
||||||
|
recipients.addAll(CommandUtil.getGroupIdentifiers(groupIdStrings));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!noNumbers) {
|
||||||
|
recipients.addAll(CommandUtil.getSingleRecipientIdentifiers(numbers, localNumber));
|
||||||
|
}
|
||||||
|
m.sendTypingMessage(action, recipients);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new Error.Failure("Failed to send message: " + e.getMessage());
|
||||||
|
} catch (GroupNotFoundException | NotAGroupMemberException | GroupSendingNotAllowedException e) {
|
||||||
|
throw new Error.InvalidGroupId("Invalid group id: " + e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new Error.UntrustedIdentity("Failed to send message: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Since contact names might be empty if not defined, also potentially return
|
// Since contact names might be empty if not defined, also potentially return
|
||||||
// the profile name
|
// the profile name
|
||||||
@Override
|
@Override
|
||||||
|
@ -404,10 +444,19 @@ public class DbusSignalImpl implements Signal {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setGroupBlocked(final byte[] groupId, final boolean blocked) {
|
public void setGroupBlocked(final byte[] groupId, final boolean blocked) {
|
||||||
|
GroupId group = null;
|
||||||
try {
|
try {
|
||||||
m.setGroupBlocked(getGroupId(groupId), blocked);
|
group = getGroupId(groupId);
|
||||||
|
} catch (AssertionError e) {
|
||||||
|
throw new Error.Failure(e.getMessage());
|
||||||
|
}
|
||||||
|
if (group == null) {
|
||||||
|
throw new Error.InvalidGroupId("GroupId is null.");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
m.setGroupBlocked(group, blocked);
|
||||||
} catch (NotMasterDeviceException e) {
|
} catch (NotMasterDeviceException e) {
|
||||||
throw new Error.Failure("This command doesn't work on linked devices.");
|
throw new Error.Failure("This command doesn't work on linked device");
|
||||||
} catch (GroupNotFoundException e) {
|
} catch (GroupNotFoundException e) {
|
||||||
throw new Error.GroupNotFound(e.getMessage());
|
throw new Error.GroupNotFound(e.getMessage());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -443,9 +492,14 @@ public class DbusSignalImpl implements Signal {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getGroupName(final byte[] groupId) {
|
public String getGroupName(final byte[] groupId) {
|
||||||
var group = m.getGroup(getGroupId(groupId));
|
org.asamk.signal.manager.api.Group group = null;
|
||||||
if (group == null || group.getTitle() == null) {
|
try {
|
||||||
return "";
|
group = m.getGroup(getGroupId(groupId));
|
||||||
|
} catch (AssertionError e) {
|
||||||
|
throw new Error.Failure(e.getMessage());
|
||||||
|
}
|
||||||
|
if (group == null) {
|
||||||
|
throw new Error.InvalidGroupId("GroupId is null.");
|
||||||
} else {
|
} else {
|
||||||
return group.getTitle();
|
return group.getTitle();
|
||||||
}
|
}
|
||||||
|
@ -453,9 +507,14 @@ public class DbusSignalImpl implements Signal {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getGroupMembers(final byte[] groupId) {
|
public List<String> getGroupMembers(final byte[] groupId) {
|
||||||
var group = m.getGroup(getGroupId(groupId));
|
org.asamk.signal.manager.api.Group group = null;
|
||||||
|
try {
|
||||||
|
group = m.getGroup(getGroupId(groupId));
|
||||||
|
} catch (AssertionError e) {
|
||||||
|
throw new Error.Failure(e.getMessage());
|
||||||
|
}
|
||||||
if (group == null) {
|
if (group == null) {
|
||||||
return List.of();
|
throw new Error.InvalidGroupId("GroupId is null.");
|
||||||
} else {
|
} else {
|
||||||
final var members = group.getMembers();
|
final var members = group.getMembers();
|
||||||
return getRecipientStrings(members);
|
return getRecipientStrings(members);
|
||||||
|
@ -638,7 +697,15 @@ public class DbusSignalImpl implements Signal {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void quitGroup(final byte[] groupId) {
|
public void quitGroup(final byte[] groupId) {
|
||||||
var group = getGroupId(groupId);
|
GroupId group = null;
|
||||||
|
try {
|
||||||
|
group = getGroupId(groupId);
|
||||||
|
} catch (AssertionError e) {
|
||||||
|
throw new Error.Failure(e.getMessage());
|
||||||
|
}
|
||||||
|
if (group == null) {
|
||||||
|
throw new Error.InvalidGroupId("GroupId is null.");
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
m.quitGroup(group, Set.of());
|
m.quitGroup(group, Set.of());
|
||||||
} catch (GroupNotFoundException | NotAGroupMemberException e) {
|
} catch (GroupNotFoundException | NotAGroupMemberException e) {
|
||||||
|
@ -673,9 +740,14 @@ public class DbusSignalImpl implements Signal {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isGroupBlocked(final byte[] groupId) {
|
public boolean isGroupBlocked(final byte[] groupId) {
|
||||||
var group = m.getGroup(getGroupId(groupId));
|
org.asamk.signal.manager.api.Group group = null;
|
||||||
|
try {
|
||||||
|
group = m.getGroup(getGroupId(groupId));
|
||||||
|
} catch (AssertionError e) {
|
||||||
|
throw new Error.Failure(e.getMessage());
|
||||||
|
}
|
||||||
if (group == null) {
|
if (group == null) {
|
||||||
return false;
|
throw new Error.InvalidGroupId("GroupId is null.");
|
||||||
} else {
|
} else {
|
||||||
return group.isBlocked();
|
return group.isBlocked();
|
||||||
}
|
}
|
||||||
|
@ -683,9 +755,14 @@ public class DbusSignalImpl implements Signal {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMember(final byte[] groupId) {
|
public boolean isMember(final byte[] groupId) {
|
||||||
var group = m.getGroup(getGroupId(groupId));
|
org.asamk.signal.manager.api.Group group = null;
|
||||||
|
try {
|
||||||
|
group = m.getGroup(getGroupId(groupId));
|
||||||
|
} catch (AssertionError e) {
|
||||||
|
throw new Error.Failure(e.getMessage());
|
||||||
|
}
|
||||||
if (group == null) {
|
if (group == null) {
|
||||||
return false;
|
throw new Error.InvalidGroupId("GroupId is null.");
|
||||||
} else {
|
} else {
|
||||||
return group.isMember();
|
return group.isMember();
|
||||||
}
|
}
|
||||||
|
@ -848,6 +925,20 @@ public class DbusSignalImpl implements Signal {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getGroupObjectPath(String basePath, byte[] groupId) {
|
private static String getGroupObjectPath(String basePath, byte[] groupId) {
|
||||||
|
/* note that DBus cannot provide a one-to-one reverse translation
|
||||||
|
* of groupPath to groupId. This is because Signal uses base64 for
|
||||||
|
* its group strings, converting any slash (/) to an underscore but
|
||||||
|
* retaining any plus (+) symbol.
|
||||||
|
*
|
||||||
|
* But DBus forbids both slash and plus, so both must be converted
|
||||||
|
* to an underscore, as DBus provides for only 63 of the 64 characters.
|
||||||
|
*
|
||||||
|
* The solution is to use the groupPath to get the Id group property,
|
||||||
|
* which is an array of bytes, then use Base64.getEncoder().encodeToString(groupId)
|
||||||
|
* to obtain the groupIdString. Note that it is theoretically possible, though
|
||||||
|
* extremely unlikely, that two different groups will map to the same groupPath.
|
||||||
|
*
|
||||||
|
*/
|
||||||
return basePath + "/Groups/" + Base64.getEncoder()
|
return basePath + "/Groups/" + Base64.getEncoder()
|
||||||
.encodeToString(groupId)
|
.encodeToString(groupId)
|
||||||
.replace("+", "_")
|
.replace("+", "_")
|
||||||
|
|
|
@ -63,12 +63,12 @@ public class CommandUtil {
|
||||||
return groupIds;
|
return groupIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GroupId getGroupId(String groupId) throws UserErrorException {
|
public static GroupId getGroupId(String groupIdString) throws UserErrorException {
|
||||||
if (groupId == null) {
|
if (groupIdString == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return GroupId.fromBase64(groupId);
|
return GroupId.fromBase64(groupIdString);
|
||||||
} catch (GroupIdFormatException e) {
|
} catch (GroupIdFormatException e) {
|
||||||
throw new UserErrorException("Invalid group id: " + e.getMessage());
|
throw new UserErrorException("Invalid group id: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue