Brought in my code and set up some unit tests to start out
This commit is contained in:
+12
@@ -29,3 +29,15 @@ out/
|
|||||||
*.eml
|
*.eml
|
||||||
*.iml
|
*.iml
|
||||||
.userlibraries
|
.userlibraries
|
||||||
|
|
||||||
|
# Maven
|
||||||
|
target/
|
||||||
|
pom.xml.tag
|
||||||
|
pom.xml.releaseBackup
|
||||||
|
pom.xml.versionsBackup
|
||||||
|
pom.xml.next
|
||||||
|
release.properties
|
||||||
|
dependency-reduced-pom.xml
|
||||||
|
buildNumber.properties
|
||||||
|
.mvn/timing.properties
|
||||||
|
.mvn/wrapper/maven-wrapper.jar
|
||||||
@@ -8,5 +8,26 @@
|
|||||||
<artifactId>ts3j</artifactId>
|
<artifactId>ts3j</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.7.0</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>RELEASE</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
package com.github.manevolent.ts3j;
|
||||||
|
|
||||||
|
import com.github.manevolent.ts3j.command.Command;
|
||||||
|
import com.github.manevolent.ts3j.command.part.CommandSingleParameter;
|
||||||
|
import com.github.manevolent.ts3j.command.response.CommandResponse;
|
||||||
|
import com.github.manevolent.ts3j.enums.ConnectionState;
|
||||||
|
import com.github.manevolent.ts3j.enums.PacketFlags;
|
||||||
|
import com.github.manevolent.ts3j.enums.PacketType;
|
||||||
|
import com.github.manevolent.ts3j.handler.TeamspeakClientHandler;
|
||||||
|
import com.github.manevolent.ts3j.util.Ts3Logging;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
public class TeamspeakClient {
|
||||||
|
private final PacketReceiver packetReceiver = new PacketReceiver();
|
||||||
|
|
||||||
|
private final DatagramSocket datagramSocket;
|
||||||
|
private final DatagramPacket datagramPacket = new DatagramPacket(new byte[1500], 1500);
|
||||||
|
|
||||||
|
private final Object connectionStateLock = new Object();
|
||||||
|
|
||||||
|
private TeamspeakClientHandler handler;
|
||||||
|
|
||||||
|
private InetSocketAddress remote = null;
|
||||||
|
private ConnectionState connectionState = null;
|
||||||
|
private int returnCodeIndex = 0;
|
||||||
|
|
||||||
|
public TeamspeakClient(DatagramSocket datagramSocket) {
|
||||||
|
this.datagramSocket = datagramSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TeamspeakClient() throws SocketException {
|
||||||
|
this(new DatagramSocket());
|
||||||
|
|
||||||
|
setConnectionState(ConnectionState.DISCONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setConnectionState(ConnectionState state) {
|
||||||
|
synchronized (connectionStateLock) {
|
||||||
|
if (state != this.connectionState) {
|
||||||
|
boolean wasDisconnected = this.connectionState == ConnectionState.DISCONNECTED;
|
||||||
|
|
||||||
|
this.connectionState = state;
|
||||||
|
|
||||||
|
if (wasDisconnected) {
|
||||||
|
Ts3Logging.debug("Starting network receiver thread...");
|
||||||
|
|
||||||
|
Thread receiverThread = new Thread(new PacketReceiver());
|
||||||
|
receiverThread.setDaemon(true);
|
||||||
|
receiverThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handler != null)
|
||||||
|
handler.handleConnectionStateChanging(state);
|
||||||
|
|
||||||
|
if (handler == null || handler.getClass() != state.getHandlerClass()) {
|
||||||
|
Ts3Logging.debug("Assigning " + state.getHandlerClass().getName() + " handler...");
|
||||||
|
|
||||||
|
handler = state.createHandler(this);
|
||||||
|
|
||||||
|
try {
|
||||||
|
handler.onAssigned();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connectionStateLock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected() {
|
||||||
|
return connectionState == ConnectionState.CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConnectionState getConnectionState() {
|
||||||
|
return connectionState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void joinConnectionState(ConnectionState state, long wait)
|
||||||
|
throws InterruptedException, TimeoutException {
|
||||||
|
synchronized (connectionStateLock) {
|
||||||
|
if (connectionState != state) {
|
||||||
|
connectionStateLock.wait(wait);
|
||||||
|
|
||||||
|
if (connectionState != state)
|
||||||
|
throw new TimeoutException("timeout waiting for " + state.name() + " state");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandResponse sendCommand(Command command) throws IOException {
|
||||||
|
if (command.willExpectResponse() && !isConnected())
|
||||||
|
throw new IOException("not connected");
|
||||||
|
|
||||||
|
CommandResponse response;
|
||||||
|
|
||||||
|
if (command.willExpectResponse()) {
|
||||||
|
int returnCodeIndex = ++ this.returnCodeIndex;
|
||||||
|
command.appendParameter(new CommandSingleParameter("return_code", returnCodeIndex));
|
||||||
|
response = new CommandResponse(command, returnCodeIndex);
|
||||||
|
} else {
|
||||||
|
response = new CommandResponse(command, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
String commandString = command.toString();
|
||||||
|
|
||||||
|
response.setDispatchedTime(System.currentTimeMillis());
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect(InetSocketAddress remote, String password, long timeout) throws IOException {
|
||||||
|
try {
|
||||||
|
if (connectionState != ConnectionState.DISCONNECTED)
|
||||||
|
throw new IllegalStateException(connectionState.name());
|
||||||
|
|
||||||
|
datagramSocket.connect(remote);
|
||||||
|
|
||||||
|
setConnectionState(ConnectionState.CONNECTING);
|
||||||
|
joinConnectionState(ConnectionState.CONNECTED, timeout);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
setConnectionState(ConnectionState.DISCONNECTED);
|
||||||
|
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(PacketType type, byte[] data) throws IOException {
|
||||||
|
C2SPacket packet = createOutgoingPacket(type, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private C2SPacket createOutgoingPacket(PacketType type, byte[] data) throws IOException {
|
||||||
|
C2SPacket packet = new C2SPacket();
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
packet.setPacketId(0);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
packet.setGenerationId(0);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
packet.setClientId(0);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
packet.packetFlags |= 0;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case VOICE:
|
||||||
|
case VOICE_WHISPER:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case COMMAND:
|
||||||
|
case COMMAND_LOW:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case PING:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case PONG:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ACK:
|
||||||
|
case ACK_LOW:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case INIT:
|
||||||
|
packet.setPacketFlags(packet.getPacketFlags() | PacketFlags.UNENCRYPTED.getIndex());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wire packet write
|
||||||
|
* @param packet Packet to write
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void sendNetworkPacket(DatagramPacket packet) throws IOException {
|
||||||
|
Ts3Logging.debug(
|
||||||
|
"[NETWORK] WRITE Len=" + packet.getLength() + " to " + datagramSocket.getRemoteSocketAddress() +
|
||||||
|
"\n" + Ts3Logging.getHex(packet.getData())
|
||||||
|
);
|
||||||
|
|
||||||
|
packet.setSocketAddress(datagramSocket.getRemoteSocketAddress());
|
||||||
|
|
||||||
|
datagramSocket.send(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DatagramPacket receiveNetworkPacket() throws IOException {
|
||||||
|
datagramSocket.receive(datagramPacket);
|
||||||
|
return datagramPacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleNetworkPacket(DatagramPacket packet) {
|
||||||
|
Ts3Logging.debug(
|
||||||
|
"[NETWORK] READ Len=" + packet.getLength() + " from " + packet.getSocketAddress() +
|
||||||
|
"\n" + Ts3Logging.getHex(packet.getData())
|
||||||
|
);
|
||||||
|
|
||||||
|
if (handler != null) handler.handleNetworkPacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InetSocketAddress getRemote() {
|
||||||
|
return remote;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PacketReceiver implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (connectionState != ConnectionState.DISCONNECTED) {
|
||||||
|
try {
|
||||||
|
handleNetworkPacket(receiveNetworkPacket());
|
||||||
|
} catch (IOException e) {
|
||||||
|
Ts3Logging.info("Problem handling packet: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ts3Logging.debug("Leaving packet receiver");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class C2SPacket {
|
||||||
|
private int packetId;
|
||||||
|
private int generationId;
|
||||||
|
private int clientId;
|
||||||
|
private int packetFlags;
|
||||||
|
|
||||||
|
private PacketType type;
|
||||||
|
private byte[] data;
|
||||||
|
private Date lastSendTime;
|
||||||
|
|
||||||
|
public PacketType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(PacketType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(byte[] data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getLastSendTime() {
|
||||||
|
return lastSendTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPacketId() {
|
||||||
|
return packetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPacketId(int packetId) {
|
||||||
|
this.packetId = packetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGenerationId() {
|
||||||
|
return generationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGenerationId(int generationId) {
|
||||||
|
this.generationId = generationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientId(int clientId) {
|
||||||
|
this.clientId = clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPacketFlags() {
|
||||||
|
return packetFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPacketFlags(int packetFlags) {
|
||||||
|
this.packetFlags = packetFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends, or re-sends, a packet
|
||||||
|
*/
|
||||||
|
public void send() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.github.manevolent.ts3j.command;
|
||||||
|
|
||||||
|
import com.github.manevolent.ts3j.command.part.CommandParameter;
|
||||||
|
|
||||||
|
public interface Command {
|
||||||
|
boolean willExpectResponse();
|
||||||
|
|
||||||
|
Iterable<CommandParameter> getParameters();
|
||||||
|
|
||||||
|
void appendParameter(CommandParameter parameter);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.github.manevolent.ts3j.command.part;
|
||||||
|
|
||||||
|
import com.github.manevolent.ts3j.enums.CommandPartType;
|
||||||
|
|
||||||
|
public class CommandOption implements CommandParameter {
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
public CommandOption(String value) {
|
||||||
|
this.value = " -" + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandPartType getType() {
|
||||||
|
return CommandPartType.OPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.github.manevolent.ts3j.command.part;
|
||||||
|
|
||||||
|
import com.github.manevolent.ts3j.enums.CommandPartType;
|
||||||
|
|
||||||
|
public interface CommandParameter {
|
||||||
|
|
||||||
|
CommandPartType getType();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package com.github.manevolent.ts3j.command.part;
|
||||||
|
|
||||||
|
import com.github.manevolent.ts3j.enums.CommandPartType;
|
||||||
|
|
||||||
|
public class CommandSingleParameter implements CommandParameter {
|
||||||
|
private final String key, value;
|
||||||
|
|
||||||
|
public CommandSingleParameter(String key, String value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandSingleParameter(String key, boolean value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = serialize(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandSingleParameter(String key, byte value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = serialize(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandSingleParameter(String key, short value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = serialize(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandSingleParameter(String key, int value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = serialize(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandSingleParameter(String key, long value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = serialize(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandSingleParameter(String key, float value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = serialize(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandSingleParameter(String key, double value) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = serialize(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandPartType getType() {
|
||||||
|
return CommandPartType.SINGLE_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String serialize(boolean value) {
|
||||||
|
return value ? "1": "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String serialize(byte value) {
|
||||||
|
return Byte.toString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String serialize(short value) {
|
||||||
|
return Short.toString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String serialize(int value) {
|
||||||
|
return Integer.toString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String serialize(long value) {
|
||||||
|
return Long.toString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String serialize(float value) {
|
||||||
|
return Float.toString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String serialize(double value) {
|
||||||
|
return Double.toString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.github.manevolent.ts3j.command.response;
|
||||||
|
|
||||||
|
import com.github.manevolent.ts3j.command.Command;
|
||||||
|
|
||||||
|
public class CommandResponse {
|
||||||
|
private final Object returnLock = new Object();
|
||||||
|
private final Command command;
|
||||||
|
private final int returnCode;
|
||||||
|
private long dispatchedTime;
|
||||||
|
|
||||||
|
public CommandResponse(Command command, int returnCode) {
|
||||||
|
this.command = command;
|
||||||
|
this.returnCode = returnCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Command getCommand() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getReturnCode() {
|
||||||
|
return returnCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandResponse join() throws InterruptedException {
|
||||||
|
synchronized (returnLock) {
|
||||||
|
returnLock.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandResponse join(int millis) throws InterruptedException {
|
||||||
|
synchronized (returnLock) {
|
||||||
|
returnLock.wait(millis);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDispatchedTime() {
|
||||||
|
return dispatchedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDispatchedTime(long dispatchedTime) {
|
||||||
|
this.dispatchedTime = dispatchedTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum ClientListOptions {
|
||||||
|
UID(1 << 0),
|
||||||
|
AWAY(1 << 1),
|
||||||
|
VOICE(1 << 2),
|
||||||
|
TIMES(1 << 3),
|
||||||
|
GROUPS(1 << 4),
|
||||||
|
INFO(1 << 5),
|
||||||
|
ICON(1 << 6),
|
||||||
|
COUNTRY(1 << 7);
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
ClientListOptions(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClientListOptions fromId(int index) {
|
||||||
|
for (ClientListOptions value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum ClientType {
|
||||||
|
FULL(0),
|
||||||
|
QUERY(1);
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
ClientType(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClientType fromId(int index) {
|
||||||
|
for (ClientType value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum CodecType {
|
||||||
|
SPEEX_NARROWBAND(0),
|
||||||
|
SPEEX_WIDEBAND(1),
|
||||||
|
SPEEX_ULTRA_WIDEBAND(2),
|
||||||
|
CELT_MONO(3),
|
||||||
|
OPUS_VOICE(4),
|
||||||
|
OPUS_MUSIC(5),
|
||||||
|
|
||||||
|
RAW(127)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
CodecType(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CodecType fromId(int index) {
|
||||||
|
for (CodecType value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum CommandPartType {
|
||||||
|
SINGLE_PARAMETER,
|
||||||
|
MULTI_PAREMTER,
|
||||||
|
OPTION;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
import com.github.manevolent.ts3j.TeamspeakClient;
|
||||||
|
import com.github.manevolent.ts3j.handler.*;
|
||||||
|
|
||||||
|
public enum ConnectionState {
|
||||||
|
CONNECTING(TeamspeakClientHandlerConnecting.class),
|
||||||
|
NEGOTIATING(TeamspeakClientHandlerNegotiating.class),
|
||||||
|
CONNECTED(TeamspeakClientHandlerConnected.class),
|
||||||
|
DISCONNECTED(TeamspeakClientHandlerDisconnected.class);
|
||||||
|
|
||||||
|
private final Class<? extends TeamspeakClientHandler> clazz;
|
||||||
|
|
||||||
|
ConnectionState(Class<? extends TeamspeakClientHandler> clazz) {
|
||||||
|
this.clazz = clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<? extends TeamspeakClientHandler> getHandlerClass() {
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TeamspeakClientHandler createHandler(TeamspeakClient client) {
|
||||||
|
try {
|
||||||
|
return clazz.getConstructor(TeamspeakClient.class).newInstance(client);
|
||||||
|
} catch (ReflectiveOperationException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum DisconnectReason {
|
||||||
|
USER_ACTION(0),
|
||||||
|
USER_OR_CHANNEL_MOVED(1),
|
||||||
|
SUBSCRIPTION_CHANGED(2),
|
||||||
|
TIMEOUT(3),
|
||||||
|
KICKED_FROM_CHANNEL(4),
|
||||||
|
KICKED_FROM_SERVER(5),
|
||||||
|
BANNED(6),
|
||||||
|
SERVER_STOPPED(7),
|
||||||
|
LEFT_SERVER(8),
|
||||||
|
CHANNEL_UPDATED(9),
|
||||||
|
SERVER_OR_CHANNEL_EDITED(10),
|
||||||
|
SERVER_SHUTDOWN(11)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
DisconnectReason(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DisconnectReason fromId(int index) {
|
||||||
|
for (DisconnectReason value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum GroupNamingMode {
|
||||||
|
UID(1 << 0),
|
||||||
|
AWAY(1 << 1),
|
||||||
|
VOICE(1 << 2),
|
||||||
|
TIMES(1 << 3),
|
||||||
|
GROUPS(1 << 4),
|
||||||
|
INFO(1 << 5),
|
||||||
|
ICON(1 << 6),
|
||||||
|
COUNTRY(1 << 7);
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
GroupNamingMode(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GroupNamingMode fromId(int index) {
|
||||||
|
for (GroupNamingMode value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum GroupType {
|
||||||
|
TEMPLATE(0),
|
||||||
|
REGULAR(1),
|
||||||
|
QUERY(2)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
GroupType(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GroupType fromId(int index) {
|
||||||
|
for (GroupType value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum GroupWhisperType {
|
||||||
|
ALL_CHANNELS(0),
|
||||||
|
CURRENT_CHANNEL(1),
|
||||||
|
ALL_PARENT_CHANNEL(2),
|
||||||
|
CHANNEL_FAMILY(3),
|
||||||
|
COMPLETE_CHANNEL_FAMILY(4),
|
||||||
|
SUBCHANNELS(5)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
GroupWhisperType(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GroupWhisperType fromId(int index) {
|
||||||
|
for (GroupWhisperType value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum HostBannerMode {
|
||||||
|
NO_ADJUST(0),
|
||||||
|
IGNORE_ASPECT_RATIO(1),
|
||||||
|
KEEP_ASPECT(2)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
HostBannerMode(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HostBannerMode fromId(int index) {
|
||||||
|
for (HostBannerMode value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum HostMessageMode {
|
||||||
|
NONE(0),
|
||||||
|
LOG(1),
|
||||||
|
MODAL(2),
|
||||||
|
MODAL_QUIT(3)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
HostMessageMode(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HostMessageMode fromId(int index) {
|
||||||
|
for (HostMessageMode value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum KickIdentifier {
|
||||||
|
CHANNEL(4),
|
||||||
|
SERVER(5)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
KickIdentifier(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KickIdentifier fromId(int index) {
|
||||||
|
for (KickIdentifier value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum LicenseType {
|
||||||
|
NO_LICENSE(0),
|
||||||
|
ATHP(1),
|
||||||
|
LAN(2),
|
||||||
|
NPL(3),
|
||||||
|
UNKNOWN(4)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
LicenseType(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LicenseType fromId(int index) {
|
||||||
|
for (LicenseType value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum LogLevel {
|
||||||
|
ERROR(1),
|
||||||
|
WARNING(2),
|
||||||
|
DEBUG(3),
|
||||||
|
INFO(4)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
LogLevel(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LogLevel fromId(int index) {
|
||||||
|
for (LogLevel value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum PacketFlags {
|
||||||
|
NONE(0x0),
|
||||||
|
FRAGMENTED(0X10),
|
||||||
|
NEW_PROTOCOL(0x20),
|
||||||
|
COMPRESSED(0x40),
|
||||||
|
UNENCRYPTED(0x80);
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
PacketFlags(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PacketFlags fromId(int index) {
|
||||||
|
for (PacketFlags value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum PacketType {
|
||||||
|
VOICE(0x0),
|
||||||
|
VOICE_WHISPER(0x1),
|
||||||
|
COMMAND(0x2),
|
||||||
|
COMMAND_LOW(0x3),
|
||||||
|
PING(0x4),
|
||||||
|
PONG(0x5),
|
||||||
|
ACK(0x6),
|
||||||
|
ACK_LOW(0x7),
|
||||||
|
INIT(0x8)
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
PacketType(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PacketType fromId(int index) {
|
||||||
|
for (PacketType value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum PermissionGroupType {
|
||||||
|
SERVER_GROUP(0),
|
||||||
|
GLOBAL_CLIENT(1),
|
||||||
|
CHANNEL(2),
|
||||||
|
CHANNEL_GROUP(3),
|
||||||
|
CHANNEL_CLIENT(4)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
PermissionGroupType(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PermissionGroupType fromId(int index) {
|
||||||
|
for (PermissionGroupType value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum PluginTargetMode {
|
||||||
|
CURRENT_CHANNEL(0),
|
||||||
|
SERVER(1),
|
||||||
|
CLIENT(2),
|
||||||
|
CURRENT_CHANNEL_SUBSCRIBED_CLIENTS(3)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
PluginTargetMode(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PluginTargetMode fromId(int index) {
|
||||||
|
for (PluginTargetMode value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum PriviledgeTokenType {
|
||||||
|
SERVER_GROUP(0),
|
||||||
|
CHANNEL_GROUP(1)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
PriviledgeTokenType(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PriviledgeTokenType fromId(int index) {
|
||||||
|
for (PriviledgeTokenType value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum TextMessageTargetMode {
|
||||||
|
PRIVATE(1),
|
||||||
|
CHANNEL(2),
|
||||||
|
SERVER(3)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
TextMessageTargetMode(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextMessageTargetMode fromId(int index) {
|
||||||
|
for (TextMessageTargetMode value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.github.manevolent.ts3j.enums;
|
||||||
|
|
||||||
|
public enum VoiceEncryptionMode {
|
||||||
|
INDIVIDUAL(0),
|
||||||
|
DISABLED(1),
|
||||||
|
ENABLED(2)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
VoiceEncryptionMode(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VoiceEncryptionMode fromId(int index) {
|
||||||
|
for (VoiceEncryptionMode value : values())
|
||||||
|
if (value.getIndex() == index) return value;
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("invalid index: " + index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.github.manevolent.ts3j.handler;
|
||||||
|
|
||||||
|
import com.github.manevolent.ts3j.TeamspeakClient;
|
||||||
|
import com.github.manevolent.ts3j.enums.ConnectionState;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
|
||||||
|
public abstract class TeamspeakClientHandler {
|
||||||
|
private final TeamspeakClient client;
|
||||||
|
|
||||||
|
protected TeamspeakClientHandler(TeamspeakClient client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleConnectionStateChanging(ConnectionState connectionState) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleNetworkPacket(DatagramPacket packet) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAssigned() throws IOException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TeamspeakClient getClient() {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.github.manevolent.ts3j.handler;
|
||||||
|
|
||||||
|
import com.github.manevolent.ts3j.TeamspeakClient;
|
||||||
|
|
||||||
|
public class TeamspeakClientHandlerConnected extends TeamspeakClientHandler {
|
||||||
|
public TeamspeakClientHandlerConnected(TeamspeakClient client) {
|
||||||
|
super(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
+80
@@ -0,0 +1,80 @@
|
|||||||
|
package com.github.manevolent.ts3j.handler;
|
||||||
|
|
||||||
|
import com.github.manevolent.ts3j.TeamspeakClient;
|
||||||
|
import com.github.manevolent.ts3j.enums.PacketType;
|
||||||
|
import com.github.manevolent.ts3j.util.Ts3Logging;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class TeamspeakClientHandlerConnecting extends TeamspeakClientHandler {
|
||||||
|
|
||||||
|
|
||||||
|
public TeamspeakClientHandlerConnecting(TeamspeakClient client) {
|
||||||
|
super(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAssigned() throws IOException {
|
||||||
|
Ts3Logging.debug("Connecting: sending Init1...");
|
||||||
|
|
||||||
|
processInit1();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the first client dispatch of the Init1 packet (C2S initial handshake packet)
|
||||||
|
*/
|
||||||
|
public void processInit1() throws IOException {
|
||||||
|
processInit1(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void processInit1(byte[] data) throws IOException {
|
||||||
|
int versionLen = 4;
|
||||||
|
int initTypeLen = 1;
|
||||||
|
Integer type = null;
|
||||||
|
|
||||||
|
if (data != null) {
|
||||||
|
type = (int) data[0];
|
||||||
|
|
||||||
|
if (data.length < initTypeLen)
|
||||||
|
throw new IllegalArgumentException("invalid Init1 packet (too short)");
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer buffer = null;
|
||||||
|
|
||||||
|
if (type == null) {
|
||||||
|
buffer = ByteBuffer.allocate(versionLen + initTypeLen + 4 + 4 + 8);
|
||||||
|
|
||||||
|
buffer.put(new byte[] { 0x09, (byte)0x83, (byte)0x8C, (byte)0xCF });
|
||||||
|
buffer.put((byte) 0x00); // initType
|
||||||
|
buffer.order(ByteOrder.BIG_ENDIAN);
|
||||||
|
buffer.putInt((int) (System.currentTimeMillis() / 1000L));
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
buffer.put((byte) random.nextInt(256)); // 4byte random
|
||||||
|
} else {
|
||||||
|
switch (type) {
|
||||||
|
case 1:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 0x7F:
|
||||||
|
// 0x7F: Some strange servers do this
|
||||||
|
// the normal client responds by starting again
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("invalid Init1 packet id: " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer == null || buffer.position() <= 0)
|
||||||
|
throw new IllegalStateException("invalid send buffer");
|
||||||
|
|
||||||
|
getClient().send(PacketType.INIT, buffer.array());
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package com.github.manevolent.ts3j.handler;
|
||||||
|
|
||||||
|
import com.github.manevolent.ts3j.TeamspeakClient;
|
||||||
|
|
||||||
|
public class TeamspeakClientHandlerDisconnected extends TeamspeakClientHandler {
|
||||||
|
public TeamspeakClientHandlerDisconnected(TeamspeakClient client) {
|
||||||
|
super(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package com.github.manevolent.ts3j.handler;
|
||||||
|
|
||||||
|
import com.github.manevolent.ts3j.TeamspeakClient;
|
||||||
|
|
||||||
|
public class TeamspeakClientHandlerNegotiating extends TeamspeakClientHandler {
|
||||||
|
public TeamspeakClientHandlerNegotiating(TeamspeakClient client) {
|
||||||
|
super(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.github.manevolent.ts3j.util;
|
||||||
|
|
||||||
|
public final class Ts3Const {
|
||||||
|
// Common Definitions
|
||||||
|
|
||||||
|
//limited length, measured in characters
|
||||||
|
public static int MaxSizeChannelName = 40;
|
||||||
|
public static int MaxSizeVirtualserverName = 64;
|
||||||
|
public static int MaxSizeClientNicknameSdk = 64;
|
||||||
|
public static int MinSizeClientNicknameSdk = 3;
|
||||||
|
public static int MaxSizeReasonMessage = 80;
|
||||||
|
|
||||||
|
//limited length, measured in bytes (utf8 encoded)
|
||||||
|
public static int MaxSizeTextMessage = 1024;
|
||||||
|
public static int MaxSizeChannelTopic = 255;
|
||||||
|
public static int MaxSizeChannelDescription = 8192;
|
||||||
|
public static int MaxSizeVirtualserverWelcomeMessage = 1024;
|
||||||
|
|
||||||
|
// Rare Definitions
|
||||||
|
|
||||||
|
//limited length, measured in characters
|
||||||
|
public static int MaxSizeClientNickname = 30;
|
||||||
|
public static int MinSizeClientNickname = 3;
|
||||||
|
public static int MaxSizeAwayMessage = 80;
|
||||||
|
public static int MaxSizeGroupName = 30;
|
||||||
|
public static int MaxSizeTalkRequestMessage = 50;
|
||||||
|
public static int MaxSizeComplainMessage = 200;
|
||||||
|
public static int MaxSizeClientDescription = 200;
|
||||||
|
public static int MaxSizeHostMessage = 200;
|
||||||
|
public static int MaxSizeHostbuttonTooltip = 50;
|
||||||
|
public static int MaxSizePokeMessage = 100;
|
||||||
|
public static int MaxSizeOfflineMessage = 4096;
|
||||||
|
public static int MaxSizeOfflineMessageSubject = 200;
|
||||||
|
|
||||||
|
//limited length, measured in bytes (utf8 encoded)
|
||||||
|
public static int MaxSizePluginCommand = 1024 * 8;
|
||||||
|
public static int MaxSizeVirtualserverHostbannerGfxUrl = 2000;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.github.manevolent.ts3j.util;
|
||||||
|
|
||||||
|
public final class Ts3Logging {
|
||||||
|
private static final String HEXES = "0123456789ABCDEF";
|
||||||
|
public static String getHex(byte[] raw) {
|
||||||
|
final StringBuilder hex = new StringBuilder(2 * raw.length);
|
||||||
|
for (final byte b : raw) {
|
||||||
|
hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
|
||||||
|
}
|
||||||
|
return hex.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void info(String message) {
|
||||||
|
System.err.println("[INFO] " + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void debug(String message) {
|
||||||
|
System.err.println("[DEBUG] " + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package com.github.manevolent.ts3j.util;
|
||||||
|
|
||||||
|
public final class Ts3String {
|
||||||
|
public static String escape(String string) {
|
||||||
|
StringBuilder sb = new StringBuilder(string.length());
|
||||||
|
|
||||||
|
for (int i = 0; i < string.length(); i ++) {
|
||||||
|
switch (string.charAt(i)) {
|
||||||
|
case '\\': sb.append("\\\\"); break;
|
||||||
|
case '/': sb.append("\\/"); break;
|
||||||
|
case ' ': sb.append("\\s"); break;
|
||||||
|
case '|': sb.append("\\p"); break;
|
||||||
|
case '\f': sb.append("\\f"); break;
|
||||||
|
case '\n': sb.append("\\n"); break;
|
||||||
|
case '\r': sb.append("\\r"); break;
|
||||||
|
case '\t': sb.append("\\t"); break;
|
||||||
|
//case '\v': sb.append("\\v"); break;
|
||||||
|
default:
|
||||||
|
sb.append(string.charAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String unescape(String string) {
|
||||||
|
StringBuilder sb = new StringBuilder(string.length());
|
||||||
|
|
||||||
|
for (int i = 0; i < string.length(); i ++) {
|
||||||
|
char c = string.charAt(i);
|
||||||
|
if (c == '\\') {
|
||||||
|
if (i++ >= string.length()) throw new IllegalArgumentException("illegal escape at end of string");
|
||||||
|
switch (string.charAt(i)) {
|
||||||
|
//case 'v': sb.append('\v'); break;
|
||||||
|
case 't': sb.append('\t'); break;
|
||||||
|
case 'r': sb.append('\r'); break;
|
||||||
|
case 'n': sb.append('\n'); break;
|
||||||
|
case 'f': sb.append('\f'); break;
|
||||||
|
case 'p': sb.append('|'); break;
|
||||||
|
case 's': sb.append(' '); break;
|
||||||
|
case '/': sb.append('/'); break;
|
||||||
|
case '\\': sb.append('\\'); break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("invalid escape code: " + c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getTokenLength(String s) {
|
||||||
|
return (int) s.length() + (int) s.chars().filter(x -> isDoubleChar((char)x)).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isDoubleChar(char c) {
|
||||||
|
return c == '\\' ||
|
||||||
|
c == '/' ||
|
||||||
|
c == ' ' ||
|
||||||
|
c == '|' ||
|
||||||
|
c == '\f' ||
|
||||||
|
c == '\n' ||
|
||||||
|
c == '\r' ||
|
||||||
|
c == '\t';// ||
|
||||||
|
//c == '\v';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.github.manevolent.ts3j;
|
||||||
|
|
||||||
|
import com.github.manevolent.ts3j.enums.ConnectionState;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
public class ServerConnectionTest extends TestCase {
|
||||||
|
public ServerConnectionTest(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testParser() throws Exception {
|
||||||
|
TeamspeakClient client = new TeamspeakClient();
|
||||||
|
|
||||||
|
client.connect(new InetSocketAddress(
|
||||||
|
"voice.teamspeak.com",
|
||||||
|
9987),
|
||||||
|
null,
|
||||||
|
10000L
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals(client.getConnectionState(), ConnectionState.CONNECTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user