Tell permission errors apart by the server's error id

The sound for a refused action was picked by looking for "permission"
or "insufficient" in the message, which also matched errors such as an
invalid permission id. The server's error ids for insufficient client,
group and permission power say it exactly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-25 10:31:28 +00:00
parent d28bb57598
commit d074ffaa7a

View File

@@ -1,6 +1,7 @@
package com.ts3client.net; package com.ts3client.net;
import com.github.manevolent.ts3j.api.Client; import com.github.manevolent.ts3j.api.Client;
import com.github.manevolent.ts3j.command.CommandException;
import com.github.manevolent.ts3j.command.MultiCommand; import com.github.manevolent.ts3j.command.MultiCommand;
import com.github.manevolent.ts3j.command.SingleCommand; import com.github.manevolent.ts3j.command.SingleCommand;
import com.github.manevolent.ts3j.command.parameter.CommandParameter; import com.github.manevolent.ts3j.command.parameter.CommandParameter;
@@ -60,6 +61,10 @@ public final class TeamspeakConnection implements TS3Listener {
private static final int REASON_KICK_CHANNEL = 4; private static final int REASON_KICK_CHANNEL = 4;
private static final int REASON_KICK_SERVER = 5; private static final int REASON_KICK_SERVER = 5;
private static final int ERROR_PERMISSIONS_CLIENT_INSUFFICIENT = 0x0a08;
private static final int ERROR_PERMISSIONS_INSUFFICIENT_GROUP_POWER = 0x0a09;
private static final int ERROR_PERMISSIONS_INSUFFICIENT_PERMISSION_POWER = 0x0a0a;
/** Shortest gap between two "you are talking while muted" reminders. */ /** Shortest gap between two "you are talking while muted" reminders. */
private static final long MUTED_TALK_COOLDOWN_NANOS = 5_000_000_000L; private static final long MUTED_TALK_COOLDOWN_NANOS = 5_000_000_000L;
@@ -431,7 +436,7 @@ public final class TeamspeakConnection implements TS3Listener {
? null : channelPassword); ? null : channelPassword);
} catch (Exception e) { } catch (Exception e) {
if (!connected) return; if (!connected) return;
error("Could not join channel \"" + target.name + "\": " + rootMessage(e)); error("Could not join channel \"" + target.name + "\": ", e);
} }
} }
@@ -1125,7 +1130,7 @@ public final class TeamspeakConnection implements TS3Listener {
/** Sends a request in the background, reporting a failure as {@code errorPrefix} and the reason. */ /** Sends a request in the background, reporting a failure as {@code errorPrefix} and the reason. */
private void act(String errorPrefix, Action action) { private void act(String errorPrefix, Action action) {
submit(action, e -> error(errorPrefix + rootMessage(e))); submit(action, e -> error(errorPrefix, e));
} }
/** Sends a request in the background whose failure nobody needs to hear about. */ /** Sends a request in the background whose failure nobody needs to hear about. */
@@ -1596,17 +1601,24 @@ public final class TeamspeakConnection implements TS3Listener {
} }
/** Reports a failure to the UI and plays the matching server sound. */ /** Reports a failure to the UI and plays the matching server sound. */
private void error(String message) { private void error(String prefix, Exception e) {
sound(isPermissionError(message) sound(isPermissionError(e)
? SoundEvent.SERVER_INSUFFICIENT_PERMISSIONS ? SoundEvent.SERVER_INSUFFICIENT_PERMISSIONS
: SoundEvent.SERVER_ERROR, serverVars()); : SoundEvent.SERVER_ERROR, serverVars());
ui.onError(message); ui.onError(prefix + rootMessage(e));
} }
private static boolean isPermissionError(String message) { /** Whether the server refused for lack of permission, wherever in the cause chain it said so. */
if (message == null) return false; private static boolean isPermissionError(Throwable t) {
String m = message.toLowerCase(java.util.Locale.ROOT); for (Throwable c = t; c != null; c = c.getCause() == c ? null : c.getCause()) {
return m.contains("insufficient") || m.contains("permission"); if (c instanceof CommandException ce) {
int id = ce.getErrorId();
return id == ERROR_PERMISSIONS_CLIENT_INSUFFICIENT
|| id == ERROR_PERMISSIONS_INSUFFICIENT_GROUP_POWER
|| id == ERROR_PERMISSIONS_INSUFFICIENT_PERMISSION_POWER;
}
}
return false;
} }
/** Whether the client is in the channel we are in ourselves. Package-private: also /** Whether the client is in the channel we are in ourselves. Package-private: also