diff --git a/ts3-client/core/src/main/java/com/ts3client/net/ConnectionEventHandler.java b/ts3-client/core/src/main/java/com/ts3client/net/ConnectionEventHandler.java index 910a471..3d3405b 100644 --- a/ts3-client/core/src/main/java/com/ts3client/net/ConnectionEventHandler.java +++ b/ts3-client/core/src/main/java/com/ts3client/net/ConnectionEventHandler.java @@ -81,6 +81,7 @@ final class ConnectionEventHandler implements TS3Listener { int from = c.channelId; c.channelId = e.getTargetChannelId(); if (e.getClientId() == conn.getSelfClientId()) { + conn.getModel().enteredChannel(e.getTargetChannelId()); announceOwnMove(safeInt(e, "reasonid"), e); logOwnMove(e, from, e.getTargetChannelId()); } else if (!c.isQuery()) { @@ -95,7 +96,10 @@ final class ConnectionEventHandler implements TS3Listener { private void logClientEntered(ClientJoinEvent e) { String name = conn.clientLink(e.getClientId(), TeamspeakConnection.orEmpty(e.getUniqueClientIdentifier()), e.getClientNickname()); - switch (safeInt(e, "reasonid")) { + // A client connecting also comes with "switched", only from no channel at all. + int reason = safeInt(e, "reasonid"); + if (reason == REASON_SWITCHED && e.getClientFromId() == 0) reason = -1; + switch (reason) { case REASON_MOVED: conn.log(name + " appears, coming from channel \"" + conn.channelLink(e.getClientFromId()) + "\""); break; @@ -116,7 +120,10 @@ final class ConnectionEventHandler implements TS3Listener { private void logClientLeft(ClientLeaveEvent e, String name) { String reasonMsg = TeamspeakConnection.orEmpty(e.get("reasonmsg")); String suffix = reasonMsg.isEmpty() ? "" : " (" + reasonMsg + ")"; - switch (safeInt(e, "reasonid")) { + int reason = safeInt(e, "reasonid"); + // A client leaving the server may also come with "switched", only to no channel at all. + if (reason == REASON_SWITCHED && e.getClientTargetId() == 0) reason = -1; + switch (reason) { case REASON_TIMEOUT: conn.log(name + " dropped (ping timeout)"); break; diff --git a/ts3-client/core/src/main/java/com/ts3client/net/ServerModel.java b/ts3-client/core/src/main/java/com/ts3client/net/ServerModel.java index 2f81ae4..5d76afb 100644 --- a/ts3-client/core/src/main/java/com/ts3client/net/ServerModel.java +++ b/ts3-client/core/src/main/java/com/ts3client/net/ServerModel.java @@ -229,6 +229,16 @@ public final class ServerModel { return channels.get(id); } + /** + * Marks the channel we are in as subscribed. The server tells us about it along with + * everything else there, but never announces the subscription for the channel we + * start out in, although it stays subscribed after we leave it. + */ + public synchronized void enteredChannel(int id) { + ChannelNode channel = channels.get(id); + if (channel != null) channel.subscribed = true; + } + public synchronized void removeChannel(int id) { ChannelNode c = channels.remove(id); if (c == null) return; 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 f6c3be7..f12af00 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 @@ -332,7 +332,10 @@ public final class TeamspeakConnection implements TS3Listener { // handshake carries, i.e. before our id was known here, so it has to be // marked once it is. ClientEntry ourselves = model.getClient(selfClientId); - if (ourselves != null) ourselves.self = true; + if (ourselves != null) { + ourselves.self = true; + model.enteredChannel(ourselves.channelId); + } fileTransfers = new FileTransferManager(client, () -> serverHost); client.setMicrophone(microphone); icons.retryFailed(); @@ -360,12 +363,13 @@ public final class TeamspeakConnection implements TS3Listener { // connect has set up in the meantime. if (connectAttempt != attempt) return; connected = false; - ui.onError("Connection failed: " + rootMessage(e) + versionHint(e)); + String failure = "Connection failed: " + rootMessage(e) + versionHint(e); + ui.onError(failure); safeCleanup(); // Report the failed attempt as a disconnect too, so the UI leaves the - // "connecting" state and the tab becomes reusable. + // "connecting" state and the tab becomes reusable. The status keeps saying why. ui.onDisconnected("connection failed"); - ui.onStatus("Disconnected"); + ui.onStatus(failure); } } @@ -1370,8 +1374,9 @@ public final class TeamspeakConnection implements TS3Listener { connected = false; safeCleanup(); announceDisconnect(false); - ui.onDisconnected(orEmpty(e.getReasonMessage())); - ui.onStatus("Disconnected"); + String reason = orEmpty(e.getReasonMessage()); + ui.onDisconnected(reason); + ui.onStatus(reason.isEmpty() ? "Disconnected" : "Disconnected: " + reason); } // ---- sound notifications ----