Hide query clients from the log and name server groups correctly

- Query clients were already left out of the tree, but their joins, moves
  and ping-timeout drops were still logged and could play sounds; TS3 keeps
  them out of sight entirely.
- The name field of notifyservergroupclientadded/deleted is the client's
  nickname, not the group's, so "added to server group" named the wrong
  thing. Resolve the group by id instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-24 15:08:18 +00:00
parent 3f65e95afd
commit 249430efad
2 changed files with 22 additions and 7 deletions

View File

@@ -50,7 +50,8 @@ final class ConnectionEventHandler implements TS3Listener {
c.serverGroupIds = parseIntList(e.getClientServerGroups()); c.serverGroupIds = parseIntList(e.getClientServerGroups());
c.channelGroupId = e.getClientChannelGroupId(); c.channelGroupId = e.getClientChannelGroupId();
c.self = (e.getClientId() == conn.getSelfClientId()); c.self = (e.getClientId() == conn.getSelfClientId());
if (e.getClientId() != conn.getSelfClientId()) { // Query clients stay out of sight, as they do in the tree and in TS3's log.
if (!c.self && !c.isQuery()) {
conn.applyContact(c); conn.applyContact(c);
announceClientEntered(e); announceClientEntered(e);
logClientEntered(e); logClientEntered(e);
@@ -60,9 +61,10 @@ final class ConnectionEventHandler implements TS3Listener {
@Override @Override
public void onClientLeave(ClientLeaveEvent e) { public void onClientLeave(ClientLeaveEvent e) {
ClientEntry gone = conn.getModel().getClient(e.getClientId());
if (e.getClientId() == conn.getSelfClientId()) { if (e.getClientId() == conn.getSelfClientId()) {
announceOwnRemoval(safeInt(e, "reasonid"), e); announceOwnRemoval(safeInt(e, "reasonid"), e);
} else { } else if (gone == null || !gone.isQuery()) {
String name = conn.clientLink(e.getClientId()); String name = conn.clientLink(e.getClientId());
announceClientLeft(e); announceClientLeft(e);
logClientLeft(e, name); logClientLeft(e, name);
@@ -81,7 +83,7 @@ final class ConnectionEventHandler implements TS3Listener {
if (e.getClientId() == conn.getSelfClientId()) { if (e.getClientId() == conn.getSelfClientId()) {
announceOwnMove(safeInt(e, "reasonid"), e); announceOwnMove(safeInt(e, "reasonid"), e);
logOwnMove(e, from, e.getTargetChannelId()); logOwnMove(e, from, e.getTargetChannelId());
} else { } else if (!c.isQuery()) {
announceClientMoved(safeInt(e, "reasonid"), e.getClientId(), from, e.getTargetChannelId()); announceClientMoved(safeInt(e, "reasonid"), e.getClientId(), from, e.getTargetChannelId());
logClientMoved(e, conn.clientLink(c.id), from, e.getTargetChannelId()); logClientMoved(e, conn.clientLink(c.id), from, e.getTargetChannelId());
} }
@@ -487,8 +489,8 @@ final class ConnectionEventHandler implements TS3Listener {
SoundEvent.YOU_SERVERGROUP_ADDED_BY_SERVER) SoundEvent.YOU_SERVERGROUP_ADDED_BY_SERVER)
: byInvoker(e, SoundEvent.CLIENT_SERVERGROUP_ADDED_BY_USER, : byInvoker(e, SoundEvent.CLIENT_SERVERGROUP_ADDED_BY_USER,
SoundEvent.CLIENT_SERVERGROUP_ADDED_BY_USER, SoundEvent.CLIENT_SERVERGROUP_ADDED_BY_SERVER), SoundEvent.CLIENT_SERVERGROUP_ADDED_BY_USER, SoundEvent.CLIENT_SERVERGROUP_ADDED_BY_SERVER),
groupVars(e.getClientId(), e.getName())); groupVars(e.getClientId(), serverGroupName(e.getServerGroupId())));
conn.log(clientLogName(e.getClientId()) + " was added to server group \"" + e.getName() conn.log(clientLogName(e.getClientId()) + " was added to server group \"" + serverGroupName(e.getServerGroupId())
+ "\" by " + invokerName(e) + "."); + "\" by " + invokerName(e) + ".");
conn.ui.onModelChanged(); conn.ui.onModelChanged();
} }
@@ -504,8 +506,8 @@ final class ConnectionEventHandler implements TS3Listener {
SoundEvent.YOU_SERVERGROUP_REMOVED_BY_USER, SoundEvent.YOU_SERVERGROUP_REMOVED_BY_SERVER) SoundEvent.YOU_SERVERGROUP_REMOVED_BY_USER, SoundEvent.YOU_SERVERGROUP_REMOVED_BY_SERVER)
: byInvoker(e, SoundEvent.CLIENT_SERVERGROUP_REMOVED_BY_USER, : byInvoker(e, SoundEvent.CLIENT_SERVERGROUP_REMOVED_BY_USER,
SoundEvent.CLIENT_SERVERGROUP_REMOVED_BY_USER, SoundEvent.CLIENT_SERVERGROUP_REMOVED_BY_SERVER), SoundEvent.CLIENT_SERVERGROUP_REMOVED_BY_USER, SoundEvent.CLIENT_SERVERGROUP_REMOVED_BY_SERVER),
groupVars(clientId, e.get("name"))); groupVars(clientId, serverGroupName(e.getServerGroupId())));
conn.log(clientLogName(clientId) + " was removed from server group \"" + TeamspeakConnection.orEmpty(e.get("name")) conn.log(clientLogName(clientId) + " was removed from server group \"" + serverGroupName(e.getServerGroupId())
+ "\" by " + invokerName(e) + "."); + "\" by " + invokerName(e) + ".");
conn.ui.onModelChanged(); conn.ui.onModelChanged();
} }
@@ -527,6 +529,15 @@ final class ConnectionEventHandler implements TS3Listener {
conn.ui.onModelChanged(); conn.ui.onModelChanged();
} }
/**
* The group's own name. The notify's {@code name} field is misleading: TeamSpeak fills
* it with the client's nickname, not the group's.
*/
private String serverGroupName(int groupId) {
Group g = conn.getModel().serverGroup(groupId);
return g != null ? g.name : "#" + groupId;
}
/** A client's name for a log line, as a link, falling back to its id once it has left. */ /** A client's name for a log line, as a link, falling back to its id once it has left. */
private String clientLogName(int clientId) { private String clientLogName(int clientId) {
return conn.clientLink(clientId); return conn.clientLink(clientId);

View File

@@ -64,6 +64,10 @@ public final class ServerModel {
return g == null ? null : g.name; return g == null ? null : g.name;
} }
public synchronized Group serverGroup(int id) {
return serverGroups.get(id);
}
/** Resolves a client's server-group ids to groups, ordered for display. */ /** Resolves a client's server-group ids to groups, ordered for display. */
public synchronized List<Group> serverGroupsOf(int[] ids) { public synchronized List<Group> serverGroupsOf(int[] ids) {
List<Group> groups = new ArrayList<>(); List<Group> groups = new ArrayList<>();