diff --git a/ts3-client/core/src/main/java/com/ts3client/net/TeamspeakConnection.java b/ts3-client/core/src/main/java/com/ts3client/net/TeamspeakConnection.java index 26875ec..a809e0d 100644 --- a/ts3-client/core/src/main/java/com/ts3client/net/TeamspeakConnection.java +++ b/ts3-client/core/src/main/java/com/ts3client/net/TeamspeakConnection.java @@ -1,6 +1,7 @@ package com.ts3client.net; 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.SingleCommand; 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_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. */ private static final long MUTED_TALK_COOLDOWN_NANOS = 5_000_000_000L; @@ -431,7 +436,7 @@ public final class TeamspeakConnection implements TS3Listener { ? null : channelPassword); } catch (Exception e) { 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. */ 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. */ @@ -1596,17 +1601,24 @@ public final class TeamspeakConnection implements TS3Listener { } /** Reports a failure to the UI and plays the matching server sound. */ - private void error(String message) { - sound(isPermissionError(message) + private void error(String prefix, Exception e) { + sound(isPermissionError(e) ? SoundEvent.SERVER_INSUFFICIENT_PERMISSIONS : SoundEvent.SERVER_ERROR, serverVars()); - ui.onError(message); + ui.onError(prefix + rootMessage(e)); } - private static boolean isPermissionError(String message) { - if (message == null) return false; - String m = message.toLowerCase(java.util.Locale.ROOT); - return m.contains("insufficient") || m.contains("permission"); + /** Whether the server refused for lack of permission, wherever in the cause chain it said so. */ + private static boolean isPermissionError(Throwable t) { + for (Throwable c = t; c != null; c = c.getCause() == c ? null : c.getCause()) { + 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