Brought in my code and set up some unit tests to start out

This commit is contained in:
Manevolent
2018-07-23 09:53:43 -04:00
parent c96a2ef0a0
commit c2dc7087ec
38 changed files with 1348 additions and 0 deletions
+12
View File
@@ -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
+21
View File
@@ -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);
}
}
@@ -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());
}
}
@@ -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);
}
}
@@ -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);
}
}