docs: comprehensive codebase analysis and reference documentation

Add full codebase analysis report, issue history, test environment
requirements, external research (TeaSpeak/ReSpeak/YaTQA), and offline
protocol references (ReSpeak ts3protocol, TeaSpeak, YaTQA). Add master
TODO list with 88 items across 11 categories. Add missing LICENSE files.

Branch: docs/codebase-analysis-v2
This commit is contained in:
Edison Jwa
2026-06-11 09:23:10 +09:00
parent 89bbfa1e18
commit 3b13a7edb4
10 changed files with 6173 additions and 0 deletions
@@ -0,0 +1,268 @@
# External Research: TeaSpeak, ReSpeak, YaTQA
**Date:** 2026-06-11
**Purpose:** Competitive analysis, dependency analysis, protocol documentation research
---
## 1. TeaSpeak
### Overview
| Attribute | Details |
|---|---|
| **Name** | TeaSpeak |
| **Website** | teaspeak.de (currently down, archived) |
| **Repository** | github.com/TeaSpeak/TeaSpeak (issue tracker only) |
| **License** | Mixed: Web Client (MPL-2.0), Server (Proprietary), TeaMusic (Open Source C++) |
| **Status** | **Effectively unmaintained** — TeaWeb archived July 2025, last server release ~2022 |
| **Stars** | 120 (main repo), 49 (TeaWeb), 7 (TeaMusic) |
| **Languages** | TypeScript (84%), SCSS, HTML, WebAssembly (web client); C++ (music bot) |
### Architecture
```
TeaSpeak Server (closed-source binary, Linux x64 only)
├── TeaSpeak Web Client (TypeScript, open source, MPL-2.0)
├── TeaSpeak Native Client (closed-source binary, Win/Linux x64)
└── TeaMusic (C++ music bot, open source)
```
### Feature Comparison
| Feature | TeaSpeak | Chanora |
|---|---|---|
| Voice (Opus) | ✅ | ✅ |
| Text Chat | ✅ (markdown) | ✅ |
| Video/Screen Sharing | ✅ (buggy, VP8) | Not planned |
| Music Bot | ✅ (built-in) | Not in scope |
| Channels | ✅ | ✅ |
| Permissions | ✅ (advanced) | Partial |
| File Transfer | ✅ | ✅ (v0.3.0) |
| Web Client | ✅ | Not in scope |
| Native Client | ✅ (closed source) | ✅ (Flutter + Rust) |
| Cross-platform | Partial (Win/Linux) | ✅ (5 platforms) |
| Push-to-Talk | Unknown | ✅ |
| i18n | ✅ (8 languages) | ✅ |
### Lessons for Chanora
**What to learn:**
- Web client as installation-less option is compelling
- Built-in music bot is popular feature
- Hidden/private channels valued by users
- Markdown in chat is well-received
- Multi-language support is expected
**What to avoid:**
- Closed-source server prevents community maintenance
- Monolithic architecture limits extensibility
- Poor maintenance (abandoned since ~2022)
- Buggy video/screen sharing (multiple open issues)
- No ARM support (frequently requested)
- Mixed tech stack (React + jQuery) creates maintenance burden
### Market Opportunity
TeaSpeak's abandonment creates a clear opportunity for Chanora:
- Users seeking open-source TeamSpeak-compatible clients
- TeaSpeak's feature set validates market need
- Chanora's formal engineering process prevents abandonment
---
## 2. ReSpeak Organization
### Overview
| Attribute | Details |
|---|---|
| **URL** | https://github.com/ReSpeak |
| **Mission** | Reverse-engineering and reimplementing TS3 protocol in Rust |
| **Activity** | 16 public repositories, 11 contributors |
| **Language focus** | Rust (primary), C, C#, Python, Svelte/TypeScript |
| **License** | Apache-2.0 / MIT dual-license |
### Repository Inventory
| Repository | Purpose | Stars | Status |
|---|---|---|---|
| **tsclientlib** | Core TS3 protocol library | 140 | Active |
| **tsdeclarations** | Machine-readable protocol declarations | 94 | Active |
| **TS3Hook** | DLL injection for packet decryption | 70 | Archived |
| **rust-ts3plugin** | Rust bindings for TS3 plugin API | 14 | Active |
| **SimpleBot** | Chat bot with custom reactions | 14 | Maintenance |
| **quicklz** | QuickLZ compression for TS3 protocol | 7 | Stable |
| **tomcrypt-rs** | Rust bindings for libtomcrypt | 6 | Dormant |
| **ts3stats** | User statistics from server logs | 6 | Dormant |
| **t4rust** | T4-like template engine for Rust | 5 | Active |
| **Qint** | Full cross-platform TS3 client (Tauri) | 5 | Active |
| **ts3tts** | Text-to-speech plugin | 3 | Maintenance |
| **TsPressor** | Message compressor | 2 | Dormant |
| **rust-ts3plugin-sys** | FFI bindings for TS3 plugin API | 0 | Active |
| **MahTsIdentity** | Identity management | 0 | Dormant |
| **pyTSon** | Python plugin interface | 0 | Dormant |
| **TsVersionChecker** | Client version verification | 1 | Dormant |
### Key Library: tsclientlib
**Architecture (monorepo):**
| Crate | Purpose |
|---|---|
| `tsclientlib` | High-level client API |
| `tsproto` | Low-level protocol (UDP, encryption, fragmentation) |
| `ts-bookkeeping` | State tracking |
| `tsproto-packets` | Packet parsing |
| `tsproto-structs` | Auto-generated structs |
| `tsproto-types` | Basic types |
**Key capabilities:**
- Full TS3 protocol handshake (Init1 RSA puzzle, ECDH key exchange)
- Encryption: EAX mode (AES-128-CTR + OMAC)
- Compression: QuickLZ level 1
- Packet fragmentation and reassembly
- Voice/Opus audio handling
**Performance:**
- ~199ms connection time (RSA puzzle dominant)
- ~189μs per message send
### Chanora's Dependency on ReSpeak
| Dependency | How Chanora Uses It |
|---|---|
| `tsclientlib` | Protocol adapter (`chanora_protocol`) |
| `tsproto` | Network layer, encryption |
| `tsproto-types` | Basic TS3 types |
| `tsproto-packets` | Packet parsing |
| `tsproto-structs` | Command/event structs |
| `ts-bookkeeping` | Server state tracking |
| `AudioHandler` | Voice decode, jitter buffer |
**Note:** Chanora uses a **fork** (`EdisonJwa/tsclientlib`) for a p256 coordinate padding fix.
### Protocol Documentation
`tsdeclarations/ts3protocol.md` is the most comprehensive open TS3 protocol specification:
1. **Low-level packets:** 9 packet types (Voice, VoiceWhisper, Command, CommandLow, Ping, Pong, Ack, AckLow, Init1)
2. **Encryption:** EAX mode (AES-128-CTR + OMAC)
3. **Compression:** QuickLZ level 1
4. **Handshake:** 5-step Init1 (RSA puzzle), then ECDH key exchange
5. **Voice:** Opus codec at 48kHz, whisper targeting modes
6. **Identity:** EC key pairs (prime256v1), hashcash proof-of-work
### Gaps in ReSpeak
| Gap | Impact on Chanora |
|---|---|
| Server code | Not needed (client only) |
| TS5 protocol | No full TS5 client protocol |
| File transfer | No implementation |
| Auto-reconnect | "Not yet there" in README |
| IPv6 support | Not documented |
| Documentation | Sparse code comments |
### Recommendations
**Continue using:**
- `tsclientlib` as primary protocol dependency
- `tsdeclarations` for protocol understanding
**Consider contributing:**
- p256 coordinate padding fix upstream
- Auto-reconnect logic if implemented
**Build internally:**
- File transfer (no existing implementation)
- Auto-reconnect logic
- TS5 compatibility (monitor `tsdeclarations`)
---
## 3. YaTQA (yat.qa)
### Overview
| Attribute | Details |
|---|---|
| **Name** | YaTQA — Yet Another TeamSpeak³ Query App |
| **URL** | https://yat.qa/ |
| **Author** | Janni "Яedeemer" K. from northern Germany |
| **First release** | June 29, 2011 |
| **Latest version** | v3.9.9b (March 1, 2023) |
| **Language** | Delphi 2009 (~50,000+ lines) |
| **Purpose** | GUI alternative to raw ServerQuery telnet commands |
**Note:** "qa" stands for **Query App**, not "Quality Assurance."
### What It Is
YaTQA is a Windows GUI tool for managing TeamSpeak 3 servers via the ServerQuery interface. It is NOT a testing framework.
### Useful Resources
The `/ressourcen/` section contains valuable unofficial documentation:
| Resource | Value for Chanora |
|---|---|
| Server error codes | Comprehensive error handling reference |
| Permission IDs | Permission feature implementation |
| Client versions | Protocol compatibility reference |
| DNS resolver behavior | Server resolution reference |
| Anti-flood mechanics | Rate limiting design |
| Codec configuration | Audio codec handling reference |
| Snapshot format | Server migration features |
| Voice client anti-flood | Rate limiting implementation |
| Other protocols | File transfer, TSDNS, blacklist, weblist, badges |
### Relevance to Chanora
**Low direct relevance** — management tool, not testing framework.
**What to extract:**
1. Unofficial ServerQuery documentation (mostly German)
2. Server error codes for comprehensive error handling
3. Permission IDs for permission features
4. Anti-flood mechanics for rate limiting design
### Codec Reference
YaTQA documents TeamSpeak's codec configuration:
- Six codecs: Speex 8kHz, Speex 16kHz, Speex 32kHz, CELT 48kHz, Opus Voice, Opus Music
- 11 quality levels per codec (010)
- Latency settings for Speex/CELT (2060ms)
- Opus is VBR (variable bitrate)
---
## 4. Summary: What Chanora Can Learn
### From TeaSpeak
- ✅ Open-source client is the right approach
- ✅ Cross-platform support is expected
- ✅ i18n is important
- ❌ Avoid closed-source components
- ❌ Avoid monolithic architecture
- ❌ Avoid mixed tech stacks
### From ReSpeak
-`tsclientlib` is the right protocol foundation
- ✅ Protocol declarations are valuable reference
- ⚠️ Keep fork in sync with upstream
- ⚠️ Monitor for TS5 protocol updates
- 🔨 Need to build file transfer internally
- 🔨 Need to build auto-reconnect internally
### From YaTQA
- 📚 Unofficial protocol docs are valuable reference
- 📚 Server error codes for error handling
- 📚 Permission IDs for permission features
- 📚 Anti-flood mechanics for rate limiting
- ❌ Not a testing framework — don't try to use it as one
---
*Generated by external research agents on 2026-06-11*
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+746
View File
@@ -0,0 +1,746 @@
# YaTQA Offline Reference — TeamSpeak 3 Protocol Documentation
**Source:** https://yat.qa/ressourcen/ (German pages)
**Author:** Janni "Яedeemer" K.
**Fetched:** 2026-06-11
**Purpose:** Offline reference for Chanora development — protocol details, error codes, undocumented features
> **Note:** The German pages contain significantly more detail than the English pages. This document captures ALL German-only content.
---
## Table of Contents
1. [Definitions and Algorithms](#1-definitions-and-algorithms)
2. [Server Query Comments](#2-server-query-comments)
3. [Server Query Notify](#3-server-query-notify)
4. [Variable Parameters](#4-variable-parameters)
5. [Voice Client Anti-Flood](#5-voice-client-anti-flood)
6. [Security Level (Hashcash)](#6-security-level-hashcash)
7. [Snapshots](#7-snapshots)
8. [Other Protocols](#8-other-protocols)
9. [Server Error Codes](#9-server-error-codes)
10. [Permission IDs](#10-permission-ids)
11. [Client Versions](#11-client-versions)
12. [Badges](#12-badges)
---
## 1. Definitions and Algorithms
### 1.1 Codecs
**Codec bitrates (b_Raw in bytes/s):**
| Codec \ Quality | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Speex Narrowband (8kHz) | 300 | 500 | 750 | 1000 | 1400 | 1900 | 2300 | 3100 | | | |
| Speex Wideband (16kHz) | 500 | 750 | 1000 | 1250 | 1600 | 2100 | 2600 | 3000 | 3500 | 4300 | 5300 |
| Speex Ultra-wideband (32kHz) | 550 | 950 | 1200 | 1450 | 1850 | 2350 | 2800 | 3200 | 3700 | 4500 | 5500 |
| CELT Mono (48kHz) | | | | | 4000 | 5000 | 6000 | 8000 | 12000 | | |
| Opus Voice | 550 | 1050 | 1550 | 2050 | 2600 | 3100 | 3600 | 4100 | 4650 | 5150 | 5650 |
| Opus Music | 900 | 1800 | 2700 | 3600 | 4500 | 5400 | 6300 | 7200 | 8100 | 9000 | 9900 |
**Key formulas:**
- `b_Official = floor(b_Raw + 45 byte / t)`
- `d = b_Raw * t + 45 byte ≤ d_Max`
- `d_Max ≈ 527 ± 1 byte` (MTU)
- `t_Max(Opus) = 20 ms`
- `t_Max(Speex/CELT) = floor((527±1 - 45) / (b_Raw * 50)) * 20 ms`
**MTU explanation:** 528 bytes (TS-MTU) + 40 bytes (IPv6 header) + 8 bytes (UDP header) = 576 bytes (old modem/ISDN MTU).
**Opus is VBR** — bitrate varies ±250 bytes/s at quality 6. Max deviation needed to reach d_Max is ~144% (never happens in practice).
### 1.2 Permission System
**Permission tiers (evaluated top to bottom, lowest wins):**
| Tier | Level | Description |
|---|---|---|
| 0 | Server Groups | Highest value wins (unless Negate flag) |
| 1 | Client (Server level) | Client-specific server permissions |
| 2 | Channel | Skipped if Skip flag set |
| 3 | Channel Group | Skipped if Skip flag set |
| 4 | Client (Channel level) | Client-specific channel permissions |
**Skip flag:** Skips channel and channel group permissions. Determined by:
1. If client permission set → use its skip flag
2. If no client permission → use effective server group's skip flag
3. If groups with Negate flag → only Negate groups count
4. If multiple groups remain → lowest ID wins
**Negate flag:** If ANY server group has Negate flag set, only groups WITH Negate flag count. Lowest ID among Negate groups wins. Even if non-Negate groups have lower IDs.
**Grant permission:** Tells how much `i_client_permission_modify_power` needed to change a permission. Grant permission name = replace first letter of original permission with `i_needed_permission_modify_power`.
**b_client_skip_channelgroup_permissions:** If set in first two tiers, ALL channel group AND channel permissions are ignored.
### 1.3 Query Connection
**Timeout behavior by version:**
| Versions | Timeout | Paragraph | Space+Enter | Command+Enter |
|---|---|---|---|---|
| 3.2.0 | 10 min | yes | yes | yes |
| 3.3.0-beta1 beta2 | 5 min | no | no | no |
| 3.3.0-beta3 3.3.1-steadyclock | 5 min | no | no* | yes |
| 3.3.1 | 5 min | no | yes | yes |
*Sending just a command keeps client on server forever (exploitable).
**Character encoding:** TeamSpeak claims UTF-8 but actually uses UCS-2 (BMP only). Mobile apps use CESU-8. Server 3.2.0 adds partial SIP support (emoji ranges).
**Line terminator:** `0x0A 0x0D` (Windows format, reversed).
**Max line length:** 9203 bytes (excluding line terminator). Not limited for 12 permission add/remove commands and `serversnapshotdeploy`.
### 1.4 Icons
- Max dimensions: 16×16
- Filename = CRC32 of icon data (same algorithm as PNG/ZIP)
- Cannot be animated
**Data types for icon IDs vary by context:**
| Context | Parameter | Read | Write |
|---|---|---|---|
| *permlist, *addpermsid | permsid=i_icon_id value= | signed | signed |
| clientlist -icon, clientinfo | client_icon_id= | signed | via clientaddperm only |
| serverinfo, serveredit | virtualserver_icon_id= | signed | unsigned |
| channellist -icon, channelinfo | channel_icon_id | signed | unsigned |
### 1.5 Avatars
- Max dimensions: 300×300
- Avatar flag = MD5 hash (not a boolean)
- Stored in channel ID 0
- Filename derived from Global ID (not from avatar flag)
- Algorithm: Base64-decode the Global ID → 20 bytes → display with `[a-p]` instead of `[0-9a-f]`
**Example calculation:**
- UID: `yGRWD2BOWPC6xSROXoi7U8NAljI=`
- Base64 decode → 20 bytes → hex: `C86456...` → filename: `migefg...`
### 1.6 Snapshots
- File starts with SHA1 hash of remaining UTF-8 data (excluding trailing newline)
- Internally runs normal Query commands when deploying
- If `serveradmin` is added to a server group, snapshot may fail on newer servers
### 1.7 Client Cache
- Subfolder names = Base64-encoded Server UID (double-encoded to avoid `/` in filenames)
- Avatars in `cache/clients/`, Icons in `cache/icons/`
- Private chat partners in `chats/clients/` (also Base64-encoded UIDs)
### 1.8 BBCode
- Max stack size: 20
- 10 tags can be active simultaneously
- Self-closing tag `[hr]` doesn't count toward stack but can't be used at 20
**Inline elements:** `[b]`, `[i]`, `[u]`, `[color=X]`, `[url=URL]Text[/url]`, `[url]URL[/url]`
**Block elements** (channel descriptions only): `[hr]`, `[size=X]`, `[img]URL[/img]`, `[left]`, `[center]`, `[right]`, `[list][*]Text[/list]`
**Internal links:**
- `client://{ClientID}/{ClientUID}~{Name}`
- `channelid://{ChannelID}` (0 = server)
- `ts3file://{Serveraddress}?port={Port}&serverUID={UID}&channel={ChannelID}&path={Path}&filename={Filename}&isDir={0|1}&size={Bytes}&fileDateTime={UnixTimestamp}`
- `ts3image://{Filename}?channel={ChannelID}&path={Path}`
**External links:**
- `ts3server://{Serveraddress}?port={Port}&nickname={Nickname}&password={Password}&channel={ChannelName}&cid={ChannelID}&channelpassword={ChannelPassword}&token={Token}&addbookmark={BookmarkName}`
**Colors:** W3C color names + `#123456` + `#123` + `transparent`
**Font sizes (since client 3.0.3):** Measured in points (pt). Legacy HTML sizes `[size=+X]` don't work — `+` prefix resets to default.
---
## 2. Server Query Comments
### 2.1 General
- `login` failure logs you out if already logged in
- `use` with non-existent server returns "server not running" error
- `use` does NOT auto-start stopped servers — must use `-virtual` flag
- `return_code` parameter available on every command
### 2.2 Key Command Issues
**serveredit:** `virtualserver_ask_for_privilegekey` setting gives error 1538 (invalid parameter).
**serversnapshotdeploy:**
- With `use` → overwrites selected server; without → creates new server
- Returns `sid` and `virtualserver_port` when creating new server
- Port not preserved from snapshot when creating new
- `-mapping` flag must come before snapshot data
**servernotifyregister:**
- Undocumented parameter `event=tokenused`
- Invalid `event` values require another parameter, then fail with parameter error
- `id=0` stands for all channels (gives duplicate events)
**sendtextmessage:** `targetmode=2` (channel) and `targetmode=3` (server) don't require `target` parameter.
**clientlist:** Undocumented `-badges` switch exists.
**clientedit:** Only `client_description` and `client_is_talker` can be modified.
**clientdblist:** `duration` is entry count (max 200), not a time duration. `-1` = maximum.
**clientdbfind:**
- Uses SQL `LIKE` matching: `%` = wildcard, `_` = single char
- Backslashes must be doubled
- Undocumented `-details` switch returns: unique_identifier, nickname, lastconnected, totalconnections, lastip
- Limited to 50 results
**clientdbedit:** Only `client_description` can be changed.
**clientgetnamefromuid:** Also returns `cldbid` — better than `clientgetdbidfromuid`.
**clientkick:** Clients to kick must come LAST in parameter list. QueryManual example is wrong.
**clientpoke:** Cannot poke multiple clients simultaneously (despite QueryManual claiming otherwise).
**privilegekeyadd:** `tokencustomset` is a self-parameterized string (spaces between params). Individual idents/values must be escaped before the entire string is escaped. QueryManual example is wrong.
### 2.3 Undocumented Commands
**plugincmd:** Parameters: `name`, `data`, `targetmode` (0-3), `target`. Only works on virtual servers. No longer allowed from Query clients.
**dummy_connectionlost:** Same as `logout` but doesn't fail if not logged in. If on a server, kicks you (connection lost). You remain invisible on instance.
**verifyserverpassword / verifychannelpassword:** Both return "not on a server" if not connected, or "command doesn't exist" if connected. Both non-functional.
**channelcreateprivate:** Returns error 2 (not implemented).
**cmd_custom_unknown_command:** Returns error 256 (command not found) — intentional.
---
## 3. Server Query Notify
### 3.1 Subscription Behavior
- Subscriptions disappear on logout, re-login, or server switch
- Must subscribe individually (no array parameter)
- Can only have ONE channel subscription at a time
- `id=0` = all channels (gives duplicate events)
- Existing subscriptions persist even if permissions revoked
### 3.2 Events
#### notifycliententerview (server + channel)
Fields: cfid, ctid, reasonid, clid, client_unique_identifier, client_nickname, client_input_muted, client_output_muted, client_outputonly_muted, client_input_hardware, client_output_hardware, client_meta_data, client_is_recording, client_database_id, client_channel_group_id, client_servergroups, client_away, client_away_message, client_type, client_flag_avatar, client_talk_power, client_talk_request, client_talk_request_msg, client_description, client_is_talker, client_is_priority_speaker, client_unread_messages, client_nickname_phonetic, client_needed_serverquery_view_power, client_icon_id, client_is_channel_commander, client_country, client_channel_group_inherited_channel_id, client_badges
#### notifyclientleftview (server + channel)
Fields: cfid, ctid, reasonid, invokerid, invokername, invokeruid, reasonmsg, bantime, clid
#### notifyserveredited (server)
Always reasonid=10. Reports new values for: name, codec_encryption_mode, default_server_group, default_channel_group, hostbanner_*, priority_speaker_dimm_modificator, hostbutton_*, name_phonetic, icon_id, hostbanner_mode, channel_temp_delete_delay_default
#### notifychannelchanged, notifychannelmoved, notifychanneledited, notifychannelcreated, notifychanneldeleted (channel)
#### notifyclientmoved (channel)
Fields: ctid, reasonid (0=self, 1=moved), invokerid, invokername, invokeruid, clid
#### notifytextmessage (textserver, textchannel, textprivate)
Fields: targetmode (1=private, 2=channel, 3=server), msg, target (only for private), invokerid, invokername, invokeruid
#### notifytokenused (tokenused — undocumented)
Fields: clid, cldbid, cluid, token, tokencustomset, token1 (group), token2 (0 for server token)
### 3.3 Reason IDs
| ID | Meaning |
|---|---|
| 0 | Self channel change or server join |
| 1 | User or channel moved |
| 3 | Timeout |
| 4 | Channel kick |
| 5 | Server kick |
| 6 | Ban |
| 8 | Voluntary server leave |
| 10 | Server or channel edited |
| 11 | Server shutdown |
---
## 4. Variable Parameters
### 4.1 Client Variables
**Key variables and their availability:**
| Variable | clientlist | clientinfo | notify | clientupdate | clientedit | clientdblist | clientdbinfo |
|---|---|---|---|---|---|---|---|
| cid | ✓ | ✓ | ✓(ctid) | | | | |
| clid | ✓ | ✓ | N/A | | | | |
| client_unique_identifier | ✓(uid) | ✓ | ✓ | ✗ | | ✓ | ✓ |
| client_nickname | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| client_input_muted | ✓(voice) | ✓ | ✓ | ✓(limited) | ✗ | | |
| client_output_muted | ✓(voice) | ✓ | ✓ | ✓(limited) | ✗ | | |
| client_database_id | ✓ | ✓ | ✓ | ✗ | | ✓(cldbid) | ✓ |
| client_servergroups | ✓(groups) | ✓ | ✓ | ✗ | | | |
| client_away | ✓(away) | ✓ | ✓ | ✓ | ✗ | | |
| client_type | ✓ | ✓ | ✓ | ✗ | | | |
| client_flag_avatar | ✓ | ✓ | ✓(modified) | ✗ | ✗ | ✓(limited) | |
| client_description | ✓ | ✓ | ✓ | ✓ | ✓ | ✓(limited) | ✓(limited) |
| client_icon_id | ✓(icon) | ✓ | ✓ | ✗ | ✗ | ✓ | ✓ |
| client_channel_group_id | ✓(groups) | ✓ | ✓ | ✗ | ✗ | | |
| client_channel_group_inherited_channel_id | ✓(groups) | ✓ | ✓ | | | | |
| client_base64HashClientUID | ✓ | ✓(limited) | | | | | |
**Notes:**
- `clientupdate` with `client_input_hardware=0` has 0 flood points (tab switch)
- `client_flag_avatar` is MD5 hash, not a boolean
- `client_badges` format: `overwolf=0:badges=GUID1=GUID2=...`
### 4.2 Channel Variables
**Key variables:**
| Variable | channellist | channelinfo | notify(created/edited/moved) | channeledit | channelcreate |
|---|---|---|---|---|---|
| cid | ✓ | ✓ | ✓ | N/A | |
| pid (parent) | ✓ | ✓ | ✓(cpid) | ✓(cpid) | ✓(cpid) |
| channel_name | ✓ | ✓ | ✓ | ✓ | ✓ |
| channel_codec | ✓(voice) | ✓ | ✓ | ✓ | ✓ |
| channel_codec_quality | ✓(voice) | ✓ | ✓ | ✓ | ✓ |
| channel_maxclients | ✓(limits) | ✓ | ✓ | ✓ | ✓ |
| channel_order | ✓ | ✓ | ✓ | ✓(order) | ✓(order) |
| channel_flag_password | ✓(flags) | ✓ | ✓ | ✓ | ✗ |
| channel_icon_id | ✓(icon) | ✓ | ✓ | ✓(limited) | ✗ |
| channel_needed_talk_power | ✓(voice) | ✓ | ✓ | ✓ | ✓ |
| channel_flag_private | ✓ | ✗ | | | |
| seconds_empty | ✓(secondsempty) | ✓ | ✗ | | |
| total_clients | ✓ | ✗ | ✗ | | |
**Notes:**
- `channel_flag_temporary` doesn't exist at all
- `channel_icon_id` changes via `channeledit` are semi-permanent (lost on restart)
- `channel_password` returns Base64(SHA1(Base64(SHA1(plaintext)) + virtualserver_keypair)) for non-Query clients
### 4.3 Server Variables
**All variables available in serverinfo. Key differences:**
| Variable | serverlist | serverinfo | serverrequestconnectioninfo | serveredit | notifyserveredited |
|---|---|---|---|---|---|
| virtualserver_name | ✓ | ✓ | | ✓ | ✓ |
| virtualserver_maxclients | ✓(limited) | ✓ | | ✓ | |
| virtualserver_port | ✓ | ✓ | | ✓ | |
| virtualserver_autostart | ✓ | ✓ | | ✓ | |
| virtualserver_icon_id | ✓ | ✓ | | ✓ | ✓ |
| virtualserver_total_packetloss_total | ✓ | ✓ | ✓(limited) | | |
| virtualserver_total_ping | ✓ | ✓ | ✓(limited) | | |
---
## 5. Voice Client Anti-Flood
### 5.1 General Rules
- Client starts with 0 points
- Every 0.5 seconds ("tick"): `virtualserver_antiflood_points_tick_reduce` points deducted (min 1)
- If `b_client_ignore_antiflood` → no points accumulated (but existing points still drain)
- Connection = 80 points (respects `b_client_ignore_antiflood`)
- `b_client_ignore_bans` bypasses IP block (but not anti-flood)
- Threshold: `virtualserver_antiflood_points_needed_command_block` blocks at EQUALITY
### 5.2 Flood Points Per Action
**High-cost actions (25 points):**
- `banadd`, `banclient`, `complainadd`, `complaindelall`, `complainlist`
- `channelcreate`, `channeldelete`, `channelmove`, `channeledit`
- `clientmove` (10), `clientkick`, `clientpoke`, `clientedit`
- `servergroupaddclient`, `servergroupdelclient`, `setclientchannelgroup`
- `clientdbdelete`, `clientdbedit`, `clientdbfind` (50!)
- `messageadd`, `messagelist`, `textmessagesend` (15)
- `logview` (50!)
**Medium-cost actions (5-15 points):**
- Most permission operations: 5 points
- Most group operations: 5 points
- File operations: 5 points (except `ftinitupload`/`ftinitdownload` = 0)
- `channelsubscribe`: 158 points!
**Zero-cost actions:**
- `clientdisconnect`, `clientgetvariables`, `clientinit`, `clientinitiv`
- `setwhisperlist`, `ftgetfilelist`, `ftinitupload`, `ftinitdownload`
- `clientmute`/`clientunmute` (0 with specific conditions)
- Internal client operations
### 5.3 Connection Flow
1. `clientinitiv`
2. `clientinit`
3. Set default channel (10 points)
4. Set badges (15 points)
5. `permissionlist` (5 points, if not cached)
6. `clientgetvariables` (0 points)
7. Subscribe channels (15-20 points)
---
## 6. Security Level (Hashcash)
### 6.1 How It Works
- Hashcash variant using SHA1
- Input: Public Key + unsigned 64-bit number (as string)
- Security level = number of leading zeros in 160-bit binary SHA1 hash
- Byte order: Big Endian, Bit order: Little Endian
### 6.2 Growth Rate
- Average 2^k hashes needed to reach level k from level 0
- Doubles for each additional level
**Time estimates (2009, modern CPUs ~4x faster):**
- Level 0-23: seconds
- Level 23-29: minutes
- Level 29-34: hours
- Level 35-39: days
- Level 40-43: months
- Level 44+: years
### 6.3 Optimization
- TeamSpeak uses single-threaded SHA1 (~1 MH/s on i5)
- Hashdog tool: multi-threaded, ~5 MH/s per core (~20-30x faster than TS)
- GPU (Hashcat): ~8.5 GH/s = 850,000% faster than TeamSpeak
- Level 33 on GTX 1080: ~1 second
---
## 7. Snapshots
### 7.1 What's Included
- Virtual server settings (except port) including keypair
- Channels
- Client database
- Permissions for local groups (both types), clients (both types), and channels
- Group assignments
### 7.2 What's NOT Included
- Server port (auto-assigned on deploy)
- Files
- Bans
- Complaints
- Offline messages (but unread count preserved)
### 7.3 Format
```
hash=Base64(SHA1(remaining_data))|snapshot_data
```
**Sections:**
1. `virtualserver_*` settings
2. `end_virtualserver|begin_channels` → channel list (tree order)
3. `end_channels|begin_clients` → client database (creation order)
4. `end_clients|begin_permissions|server_groups` → server group permissions
5. `end_groups|iid=0` → server group memberships (by cldbid, then sgid)
6. `end_relations|channel_groups` → channel group permissions
7. `end_groups|` → channel group memberships
8. `end_relations|client_flat` → client permissions (server level)
9. `end_flat|channel_flat` → channel permissions
10. `end_flat|channel_client_flat` → client-channel permissions
11. `end_flat|end_permissions`
---
## 8. Other Protocols
### 8.1 Protobuf Format
**Two key data types:**
**BigNum (Varint):**
```
if x < 128: write byte x
else: write (x mod 128 OR 128), recurse with x >> 7
```
**Binary data with length prefix:** BigNum length + raw data
**File format:** Pairs of (BigNum identifier, data) until EOF.
- Identifier AND 7 = data type (0=BigNum, 1=64-bit, 2=binary, 5=32-bit)
- Identifier SHR 3 = field number
### 8.2 Update Protocol
- Current: Downloads `ts3-client-2` from `versions.teamspeak.com` (Protobuf format)
- Contains: server version (3.0.10, outdated), stable/beta/alpha client versions
- Updater images: gzip compressed (despite `.compress` extension)
### 8.3 File Transfer
- Send key received from `ftinitupload`/`ftinitdownload` to server IP:port
- No escaping, nothing before/after
- Upload: send key then data
- Download: receive data from server
### 8.4 TSDNS
- Input → lowercase → UTF-8/CESU-8 → append `0x0A 0x0D 0x0D 0x0D 0x0A` → TCP to port 41144
- Returns IP or `404`
- `$PORT` = keep user's port
### 8.5 DNS Resolution Order
1. **SRV TS3:** `_ts3._udp.INPUT` — port overrides user input
2. **SRV TSDNS:** `_tsdns._tcp.DOMAIN`
3. **TSDNS:** Port 41144
4. **DNS:** AAAA, A records (CNAME implicit)
**First complete resolution wins. No fallback on connection failure.**
### 8.6 Blacklist (v1)
- UDP to `blacklist.teamspeak.com:17385`
- Send: `ip4:RESOLVED_IP`
- Response: `x,13371337133` where x = 0 (blacklisted), 1 (OK), 2 (greylisted)
- No response → connect anyway
### 8.7 Blacklist2 (v2, since 3.1.6)
- HTTPS POST to `blacklist2.teamspeak.com/check`
- Content-Type: `application/x-ts3blacklist`
- Protobuf-encoded `BlacklistInfoRequest` with: ip_address, domain_name, virtual_server_id, public_license_id, port, timestamp, valid_token_present, slots_ok
- Response: 8 bytes Protobuf with status_ip, status_domain, status_virtual_server_id, status_public_license_id (1=INVALID, 2=BLACKLISTED, 3=GREYLISTED, 4=NOT_LISTED)
**IPv6 canonicalization bug (3.1.6-3.1.7):** Missing blocks filled with `3030` instead of `0`. Fixed in 3.1.8-beta1.
### 8.8 Weblist (Server)
- UDP to `weblist.teamspeak.com:2010`
- Packet format: 1 byte version (always 1), 2 bytes sequence number, 1 byte type (1=key request, 2=data), payload
- Update cycle: request key → send data (key + port + slots + clients + flags + name)
- Server updates every 10 minutes, retries at 1.3s and 2s intervals
### 8.9 Badges
- Stored as GUIDs on server
- Binary list from `badges-content.teamspeak.com/list` (Protobuf format)
- Cached in `cache/badges`
- Refreshed every 24 hours
**Protobuf structure:**
1. BigNum: revision number
2. BigNum: Unix timestamp
3. For each badge: GUID, name, URL base, description, timestamp, unknown field (1-3)
---
## 9. Server Error Codes
**Complete error code list (from English page):**
| Hex | Dec | Message |
|---|---|---|
| 0x0000 | 0 | ok |
| 0x0001 | 1 | undefined error |
| 0x0002 | 2 | not implemented |
| 0x0100 | 256 | command not found |
| 0x0101 | 257 | unable to bind network port |
| 0x0200 | 512 | invalid clientID |
| 0x0201 | 513 | nickname is already in use |
| 0x0203 | 515 | max clients protocol limit reached |
| 0x0204 | 516 | invalid client type |
| 0x0205 | 517 | already subscribed |
| 0x0206 | 518 | not logged in |
| 0x0207 | 519 | could not validate client identity |
| 0x0208 | 520 | invalid loginname or password |
| 0x0209 | 521 | too many clones already connected |
| 0x020a | 522 | client version outdated |
| 0x020b | 523 | client is online |
| 0x020c | 524 | client is flooding |
| 0x020d | 525 | client is modified |
| 0x020e | 526 | can not verify client at this moment |
| 0x020f | 527 | client is not permitted to log in |
| 0x0210 | 528 | client is not subscribed to the channel |
| 0x0300 | 768 | invalid channelID |
| 0x0301 | 769 | max channels protocol limit reached |
| 0x0302 | 770 | already member of channel |
| 0x0303 | 771 | channel name is already in use |
| 0x0304 | 772 | channel not empty |
| 0x0305 | 773 | can not delete default channel |
| 0x0306 | 774 | default channel requires permanent |
| 0x0307 | 775 | invalid channel flags |
| 0x0308 | 776 | permanent channel can not be child of non permanent channel |
| 0x0309 | 777 | channel maxclient reached |
| 0x030a | 778 | channel maxfamily reached |
| 0x030b | 779 | invalid channel order |
| 0x030c | 780 | channel does not support filetransfers |
| 0x030d | 781 | invalid channel password |
| 0x030e | 782 | channel is private channel |
| 0x030f | 783 | invalid security hash supplied by client |
| 0x0400 | 1024 | invalid serverID |
| 0x0401 | 1025 | server is running |
| 0x0402 | 1026 | server is shutting down |
| 0x0403 | 1027 | server maxclient reached |
| 0x0404 | 1028 | invalid server password |
| 0x0405 | 1029 | deployment active |
| 0x0406 | 1030 | unable to stop own server |
| 0x0407 | 1031 | server is virtual |
| 0x0408 | 1032 | server wrong machineID |
| 0x0409 | 1033 | server is not running |
| 0x040a | 1034 | server is booting up |
| 0x040b | 1035 | server got an invalid status |
| 0x040c | 1036 | server modal quit |
| 0x040d | 1037 | server version is too old for command |
| 0x0410 | 1040 | server blacklisted |
| 0x0500 | 1280 | database error |
| 0x0501 | 1281 | database empty result set |
| 0x0502 | 1282 | database duplicate entry |
| 0x0503 | 1283 | database no modifications |
| 0x0504 | 1284 | database invalid constraint |
| 0x0505 | 1285 | database reinvoke command |
| 0x0600 | 1536 | invalid quote |
| 0x0601 | 1537 | invalid parameter count |
| 0x0602 | 1538 | invalid parameter |
| 0x0603 | 1539 | parameter not found |
| 0x0604 | 1540 | convert error |
| 0x0605 | 1541 | invalid parameter size |
| 0x0606 | 1542 | missing required parameter |
| 0x0607 | 1543 | invalid checksum |
| 0x0700 | 1792 | virtual server got a critical error |
| 0x0701 | 1793 | connection lost |
| 0x0702 | 1794 | not connected |
| 0x0703 | 1795 | no cached connection info |
| 0x0704 | 1796 | currently not possible |
| 0x0705 | 1797 | failed connection initialization |
| 0x0706 | 1798 | could not resolve hostname |
| 0x0707 | 1799 | invalid server connection handler ID |
| 0x0708 | 1800 | could not initialize Input Manager |
| 0x0709 | 1801 | client library not initialized |
| 0x070a | 1802 | server library not initialized |
| 0x070b | 1803 | too many whisper targets |
| 0x070c | 1804 | no whisper targets found |
| 0x0800 | 2048 | invalid file name |
| 0x0801 | 2049 | invalid file permissions |
| 0x0802 | 2050 | file already exists |
| 0x0803 | 2051 | file not found |
| 0x0804 | 2052 | file input/output error |
| 0x0805 | 2053 | invalid file transfer ID |
| 0x0806 | 2054 | invalid file path |
| 0x0807 | 2055 | no files available |
| 0x0808 | 2056 | overwrite excludes resume |
| 0x0809 | 2057 | invalid file size |
| 0x080a | 2058 | file already in use |
| 0x080b | 2059 | could not open file transfer connection |
| 0x080c | 2060 | no space left on device |
| 0x080d | 2061 | file exceeds file system's maximum file size |
| 0x080e | 2062 | file transfer connection timeout |
| 0x080f | 2063 | lost file transfer connection |
| 0x0810 | 2064 | file exceeds supplied file size |
| 0x0811 | 2065 | file transfer complete |
| 0x0812 | 2066 | file transfer canceled |
| 0x0813 | 2067 | file transfer interrupted |
| 0x0814 | 2068 | file transfer server quota exceeded |
| 0x0815 | 2069 | file transfer client quota exceeded |
| 0x0816 | 2070 | file transfer reset |
| 0x0817 | 2071 | file transfer limit reached |
| 0x0900 | 2304 | preprocessor disabled |
| 0x0901 | 2305 | internal preprocessor |
| 0x0902 | 2306 | internal encoder |
| 0x0903 | 2307 | internal playback |
| 0x0904 | 2308 | no capture device available |
| 0x0905 | 2309 | no playback device available |
| 0x0906 | 2310 | could not open capture device |
| 0x0907 | 2311 | could not open playback device |
| 0x090f | 2319 | device still in use |
| 0x0910 | 2320 | device already registered |
| 0x0911 | 2321 | device not registered/known |
| 0x0912 | 2322 | unsupported frequency |
| 0x0913 | 2323 | invalid channel count |
| 0x0a00 | 2560 | invalid group ID |
| 0x0a01 | 2561 | duplicate entry |
| 0x0a02 | 2562 | invalid permission ID |
| 0x0a03 | 2563 | empty result set |
| 0x0a04 | 2564 | access to default group is forbidden |
| 0x0a05 | 2565 | invalid size |
| 0x0a06 | 2566 | invalid value |
| 0x0a07 | 2567 | group is not empty |
| 0x0a08 | 2568 | insufficient client permissions |
| 0x0a09 | 2569 | insufficient group modify power |
| 0x0a0a | 2570 | insufficient permission modify power |
| 0x0a0b | 2571 | template group is currently used |
| 0x0a0c | 2572 | permission error |
| 0x0b00 | 2816 | virtualserver limit reached |
| 0x0b01 | 2817 | max slot limit reached |
| 0x0b02 | 2818 | license file not found |
| 0x0b03 | 2819 | license date not ok |
| 0x0b04 | 2820 | unable to connect to accounting server |
| 0x0b05 | 2821 | unknown accounting error |
| 0x0b06 | 2822 | accounting server error |
| 0x0b07 | 2823 | instance limit reached |
| 0x0b08 | 2824 | instance check error |
| 0x0b09 | 2825 | license file invalid |
| 0x0b0a | 2826 | virtualserver is running elsewhere |
| 0x0b0b | 2827 | virtualserver running in same instance already |
| 0x0b0c | 2828 | virtualserver already started |
| 0x0b0d | 2829 | virtualserver not started |
| 0x0c00 | 3072 | invalid message id |
| 0x0d00 | 3328 | invalid ban id |
| 0x0d01 | 3329 | connection failed, you are banned |
| 0x0d02 | 3330 | rename failed, new name is banned |
| 0x0d03 | 3331 | flood ban |
| 0x0e00 | 3584 | unable to initialize tts |
| 0x0f00 | 3840 | invalid privilege key |
| 0x1000 | 4096 | VoIP pjsua error |
| 0x1100 | 4352 | provisioning invalid password |
| 0x1101 | 4353 | provisioning invalid request |
| 0x1102 | 4354 | no (more) slots available |
| 0x1103 | 4355 | pool missing |
| 0x1104 | 4356 | pool unknown |
| 0x1105 | 4357 | unknown ip location |
| 0x1106 | 4358 | internal error (tries exceeded) |
| 0x1107 | 4359 | too many slots requested |
| 0x1108 | 4360 | too many reserved |
| 0x1109 | 4361 | could not connect to provisioning server |
| 0x1110 | 4368 | authentication server not connected |
| 0x1111 | 4369 | authentication data too large |
| 0x1112 | 4370 | already initialized |
| 0x1113 | 4371 | not initialized |
| 0x1114 | 4372 | already connecting |
| 0x1115 | 4373 | already connected |
| 0x1116 | 4374 | not connected |
| 0x1117 | 4375 | io_error |
| 0x1118 | 4376 | invalid timeout |
| 0x1119 | 4377 | ts3server not found |
| 0x111A | 4378 | unknown permissionID |
---
## 10. Permission IDs
**Source:** https://yat.qa/resources/permission-ids/ (English)
> See ReSpeak/tsdeclarations/Permissions.csv for the complete machine-readable list.
---
## 11. Client Versions
**Source:** https://yat.qa/resources/client-versions/ (English)
> See ReSpeak/tsdeclarations/Versions.csv for the complete machine-readable list with version hashes.
---
## 12. Badges
**Source:** https://yat.qa/ressourcen/abzeichen-badges/ (German)
> See ReSpeak/tsdeclarations/Badges.csv for the complete machine-readable list.
---
*Fetched and compiled on 2026-06-11*