Skip to content
Snippets Groups Projects
Select Git revision
  • 4fcd70834a29cb66be3bdd8de8711d0780ac31e0
  • master default protected
2 results

plugin.cpp

Blame
  • user avatar
    Carsten Fuhrmann authored
    disabled debug window,
    double mute/unmute yourself when double klick,
    using no focus instead of delegate => style file works, but icons are blue again,
    4fcd7083
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    plugin.cpp 32.82 KiB
    /*
    * TeamSpeak 3 demo plugin
    *
    * Copyright (c) 2008-2016 TeamSpeak Systems GmbH
    */
    
    #ifdef _WIN32
    #pragma warning (disable : 4100)  /* Disable Unreferenced parameter warning */
    #include <Windows.h>
    #endif
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
    #include "teamspeak/public_errors.h"
    #include "teamspeak/public_errors_rare.h"
    #include "teamspeak/public_definitions.h"
    #include "teamspeak/public_rare_definitions.h"
    #include "teamspeak/clientlib_publicdefinitions.h"
    #include "ts3_functions.h"
    #include "plugin.h"
    #include <QMap>
    
    #pragma region defines, global variables
    
    static struct TS3Functions ts3Functions;
    
    #ifdef _WIN32
    #define _strcpy(dest, destSize, src) strcpy_s(dest, destSize, src)
    #define snprintf sprintf_s
    #else
    #define _strcpy(dest, destSize, src) { strncpy(dest, src, destSize-1); (dest)[destSize-1] = '\0'; }
    #endif
    
    #define PLUGIN_API_VERSION 21
    
    #define PATH_BUFSIZE 512
    #define COMMAND_BUFSIZE 128
    #define INFODATA_BUFSIZE 128
    #define SERVERINFO_BUFSIZE 256
    #define CHANNELINFO_BUFSIZE 512
    #define RETURNCODE_BUFSIZE 128
    
    static char* pluginID = NULL;
    
    QMap<uint64, OverlayController*> g_serverList;
    
    #ifdef _WIN32
    /* Helper function to convert wchar_T to Utf-8 encoded strings on Windows */
    static int wcharToUtf8(const wchar_t* str, char** result) {
    	int outlen = WideCharToMultiByte(CP_UTF8, 0, str, -1, 0, 0, 0, 0);
    	*result = (char*)malloc(outlen);
    	if (WideCharToMultiByte(CP_UTF8, 0, str, -1, *result, outlen, 0, 0) == 0) {
    		*result = NULL;
    		return -1;
    	}
    	return 0;
    }
    #endif
    
    #pragma endregion
    
    
    /****************************** Helper functions ********************************/
    /*
    * Following functions are helper for the callbacks.
    */
    
    #pragma region helper functions
    
    uint64 getCurrentChannel(uint64 serverConnectionHandlerID)
    {
    	uint64 curChannel;
    	anyID curClient;
    
    	ts3Functions.getClientID(serverConnectionHandlerID, &curClient);
    	ts3Functions.getChannelOfClient(serverConnectionHandlerID, curClient, &curChannel);
    
    	return curChannel;
    }
    
    QString clientID2Name(uint64 serverConnectionHandlerID, anyID clientID)
    {
    	char* tmp;
    	if (ts3Functions.getClientVariableAsString(serverConnectionHandlerID, clientID, CLIENT_NICKNAME, &tmp) != ERROR_ok)
    		return QString();
    
    	QString name(tmp);
    	ts3Functions.freeMemory(tmp);
    	return name;
    }
    
    QString channelID2Name(uint64 serverConnectionHandlerID, uint64 channelID)
    {
    	char* tmp;
    	if (ts3Functions.getChannelVariableAsString(serverConnectionHandlerID, channelID, CHANNEL_NAME, &tmp) != ERROR_ok)
    		return QString();
    
    	QString name(tmp);
    	ts3Functions.freeMemory(tmp);
    	return name;
    }
    
    OverlayController* getController(uint64 serverConnectionHandlerID = 0)
    {
    	if (serverConnectionHandlerID == 0)
    	{
    		OverlayController* ret = NULL;
    
    		for (auto it : g_serverList.keys())
    		{
    			int tmp;
    
    			if (ts3Functions.getClientSelfVariableAsInt(it, CLIENT_INPUT_HARDWARE, &tmp) == ERROR_ok)
    				if (tmp == 1)
    					ret = g_serverList.find(it).value();
    		}
    		return ret;
    	}
    
    	auto tmp = g_serverList.find(serverConnectionHandlerID);
    
    	if (tmp == g_serverList.end())
    	{
    		OverlayController* ret = new OverlayController(ts3Functions, serverConnectionHandlerID);
    		g_serverList.insert(serverConnectionHandlerID, ret);
    		return ret;
    	}
    
    	return tmp.value();
    }
    
    void setActiveServer(uint64 serverConnectionHanderlID)
    {
    	// mute all server
    	for (auto& it : g_serverList)
    		it->mute(true);
    
    	// unmute the current server
    	getController(serverConnectionHanderlID)->mute(false);
    }
    
    /* Helper function to create a hotkey */
    static struct PluginHotkey* createHotkey(const char* keyword, const char* description) {
    	struct PluginHotkey* hotkey = (struct PluginHotkey*)malloc(sizeof(struct PluginHotkey));
    	_strcpy(hotkey->keyword, PLUGIN_HOTKEY_BUFSZ, keyword);
    	_strcpy(hotkey->description, PLUGIN_HOTKEY_BUFSZ, description);
    	return hotkey;
    }
    
    /* Some makros to make the code to create hotkeys a bit more readable */
    #define BEGIN_CREATE_HOTKEYS(x) const size_t sz = x + 1; size_t n = 0; *hotkeys = (struct PluginHotkey**)malloc(sizeof(struct PluginHotkey*) * sz);
    #define CREATE_HOTKEY(a, b) (*hotkeys)[n++] = createHotkey(a, b);
    #define END_CREATE_HOTKEYS (*hotkeys)[n++] = NULL; assert(n == sz);
    
    #pragma endregion
    
    
    /*********************************** Required functions ************************************/
    /*
    * If any of these required functions is not implemented, TS3 will refuse to load the plugin
    */
    
    #pragma region required functions
    
    /* Unique name identifying this plugin */
    const char* ts3plugin_name() {
    #ifdef _WIN32
    	/* TeamSpeak expects UTF-8 encoded characters. Following demonstrates a possibility how to convert UTF-16 wchar_t into UTF-8. */
    	static char* result = NULL;  /* Static variable so it's allocated only once */
    	if (!result) {
    		const wchar_t* name = L"Cute Overlay";
    		if (wcharToUtf8(name, &result) == -1) {  /* Convert name into UTF-8 encoded result */
    			result = "Cute Overlay";  /* Conversion failed, fallback here */
    		}
    	}
    	return result;
    #else
    	return "Cute Overlay";
    #endif
    }
    
    /* Plugin version */
    const char* ts3plugin_version() {
    	return "1.1";
    }
    
    /* Plugin API version. Must be the same as the clients API major version, else the plugin fails to load. */
    int ts3plugin_apiVersion() {
    	return PLUGIN_API_VERSION;
    }
    
    /* Plugin author */
    const char* ts3plugin_author() {
    	/* If you want to use wchar_t, see ts3plugin_name() on how to use */
    	return "GT-Anakin";
    }
    
    /* Plugin description */
    const char* ts3plugin_description() {
    	/* If you want to use wchar_t, see ts3plugin_name() on how to use */
    	return "This plugin is a simple overlay based on Qt";
    }
    
    /* Set TeamSpeak 3 callback functions */
    void ts3plugin_setFunctionPointers(const struct TS3Functions funcs) {
    	ts3Functions = funcs;
    }
    
    /*
    * Custom code called right after loading the plugin. Returns 0 on success, 1 on failure.
    * If the function returns 1 on failure, the plugin will be unloaded again.
    */
    int ts3plugin_init() {
    	char pluginPath[PATH_BUFSIZE];
    
    	ts3Functions.getPluginPath(pluginPath, PATH_BUFSIZE, pluginID);
    
    	return 0;  /* 0 = success, 1 = failure, -2 = failure but client will not show a "failed to load" warning */
    			   /* -2 is a very special case and should only be used if a plugin displays a dialog (e.g. overlay) asking the user to disable
    			   * the plugin again, avoiding the show another dialog by the client telling the user the plugin failed to load.
    			   * For normal case, if a plugin really failed to load because of an error, the correct return value is 1. */
    }
    
    /* Custom code called right before the plugin is unloaded */
    void ts3plugin_shutdown() {
    
    	while (g_serverList.size() > 0)
    		delete g_serverList.take(g_serverList.firstKey());
    
    	if (pluginID) {
    		free(pluginID);
    		pluginID = NULL;
    	}
    
    	/*
    	* Note:
    	* If your plugin implements a settings dialog, it must be closed and deleted here, else the
    	* TeamSpeak client will most likely crash (DLL removed but dialog from DLL code still open).
    	*/
    }
    
    #pragma endregion
    
    
    /****************************** Optional functions ********************************/
    /*
    * Following functions are optional, if not needed you don't need to implement them.
    */
    
    #pragma region optional functions
    
    /* Tell client if plugin offers a configuration window. If this function is not implemented, it's an assumed "does not offer" (PLUGIN_OFFERS_NO_CONFIGURE). */
    int ts3plugin_offersConfigure() {
    	/*
    	* Return values:
    	* PLUGIN_OFFERS_NO_CONFIGURE         - Plugin does not implement ts3plugin_configure
    	* PLUGIN_OFFERS_CONFIGURE_NEW_THREAD - Plugin does implement ts3plugin_configure and requests to run this function in an own thread
    	* PLUGIN_OFFERS_CONFIGURE_QT_THREAD  - Plugin does implement ts3plugin_configure and requests to run this function in the Qt GUI thread
    	*/
    	return PLUGIN_OFFERS_NO_CONFIGURE;  /* In this case ts3plugin_configure does not need to be implemented */
    }
    
    /* Plugin might offer a configuration window. If ts3plugin_offersConfigure returns 0, this function does not need to be implemented. */
    void ts3plugin_configure(void* handle, void* qParentWidget) {
    
    }
    
    /*
    * If the plugin wants to use error return codes, plugin commands, hotkeys or menu items, it needs to register a command ID. This function will be
    * automatically called after the plugin was initialized. This function is optional. If you don't use these features, this function can be omitted.
    * Note the passed pluginID parameter is no longer valid after calling this function, so you must copy it and store it in the plugin.
    */
    void ts3plugin_registerPluginID(const char* id) {
    	const size_t sz = strlen(id) + 1;
    	pluginID = (char*)malloc(sz * sizeof(char));
    	_strcpy(pluginID, sz, id);
    }
    
    /* Plugin command keyword. Return NULL or "" if not used. */
    const char* ts3plugin_commandKeyword() {
    	return NULL;
    }
    
    /* Plugin processes console command. Return 0 if plugin handled the command, 1 if not handled. */
    int ts3plugin_processCommand(uint64 serverConnectionHandlerID, const char* command) {
    	return 1;  /* Plugin handled command */
    }
    
    /* Client changed current server connection handler */
    void ts3plugin_currentServerConnectionChanged(uint64 serverConnectionHandlerID) {
    }
    
    /*
    * Implement the following three functions when the plugin should display a line in the server/channel/client info.
    * If any of ts3plugin_infoTitle, ts3plugin_infoData or ts3plugin_freeMemory is missing, the info text will not be displayed.
    */
    
    /* Static title shown in the left column in the info frame */
    const char* ts3plugin_infoTitle() {
    	return "";
    }
    
    /*
    * Dynamic content shown in the right column in the info frame. Memory for the data string needs to be allocated in this
    * function. The client will call ts3plugin_freeMemory once done with the string to release the allocated memory again.
    * Check the parameter "type" if you want to implement this feature only for specific item types. Set the parameter
    * "data" to NULL to have the client ignore the info data.
    */
    void ts3plugin_infoData(uint64 serverConnectionHandlerID, uint64 id, enum PluginItemType type, char** data) {
    }
    
    /* Required to release the memory for parameter "data" allocated in ts3plugin_infoData and ts3plugin_initMenus */
    void ts3plugin_freeMemory(void* data) {
    	free(data);
    }
    
    /*
    * Plugin requests to be always automatically loaded by the TeamSpeak 3 client unless
    * the user manually disabled it in the plugin dialog.
    * This function is optional. If missing, no autoload is assumed.
    */
    int ts3plugin_requestAutoload() {
    	return 0;  /* 1 = request autoloaded, 0 = do not request autoload */
    }
    
    /*
    * Initialize plugin hotkeys. If your plugin does not use this feature, this function can be omitted.
    * Hotkeys require ts3plugin_registerPluginID and ts3plugin_freeMemory to be implemented.
    * This function is automatically called by the client after ts3plugin_init.
    */
    void ts3plugin_initHotkeys(struct PluginHotkey*** hotkeys) {
    	/* Register hotkeys giving a keyword and a description.
    	* The keyword will be later passed to ts3plugin_onHotkeyEvent to identify which hotkey was triggered.
    	* The description is shown in the clients hotkey dialog. */
    	BEGIN_CREATE_HOTKEYS(1);  /* Create 3 hotkeys. Size must be correct for allocating memory. */
    	CREATE_HOTKEY("Channellist", "Displays a simple channellist of the server");
    	END_CREATE_HOTKEYS;
    
    	/* The client will call ts3plugin_freeMemory to release all allocated memory */
    }
    
    #pragma endregion
    
    
    /************************** TeamSpeak callbacks ***************************/
    /*
    * Following functions are optional, feel free to remove unused callbacks.
    * See the clientlib documentation for details on each function.
    */
    
    #pragma region callbacks clientlib
    
    /* Clientlib */
    
    void ts3plugin_onConnectStatusChangeEvent(uint64 serverConnectionHandlerID, int newStatus, unsigned int errorNumber) {
    	
    	if (newStatus == STATUS_DISCONNECTED)
    	{
    		auto tmp = g_serverList.take(serverConnectionHandlerID);
    		delete tmp;
    	}
    	else if (newStatus == STATUS_CONNECTED)
    	{
    		// let helper insert new controller to avoid double entries
    		getController(serverConnectionHandlerID);
    	}
    	else if (newStatus == STATUS_CONNECTION_ESTABLISHED)
    	{
    		getController(serverConnectionHandlerID)->updateChannelList();
    		getController(serverConnectionHandlerID)->updateClientList();
    		getController(serverConnectionHandlerID)->displayChannelList();
    	}
    }
    
    void ts3plugin_onNewChannelEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 channelParentID) {
    }
    
    void ts3plugin_onNewChannelCreatedEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 channelParentID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) {
    	getController(serverConnectionHandlerID)->updateChannelList();
    	getController(serverConnectionHandlerID)->updateClientList();
    }
    
    void ts3plugin_onDelChannelEvent(uint64 serverConnectionHandlerID, uint64 channelID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) {
    	getController(serverConnectionHandlerID)->updateChannelList();
    	getController(serverConnectionHandlerID)->updateClientList();
    }
    
    void ts3plugin_onChannelMoveEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 newChannelParentID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) {
    	getController(serverConnectionHandlerID)->updateChannelList();
    	getController(serverConnectionHandlerID)->updateClientList();
    }
    
    void ts3plugin_onUpdateChannelEvent(uint64 serverConnectionHandlerID, uint64 channelID) {
    }
    
    void ts3plugin_onUpdateChannelEditedEvent(uint64 serverConnectionHandlerID, uint64 channelID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) {
    	getController(serverConnectionHandlerID)->updateChannelList();
    	getController(serverConnectionHandlerID)->updateClientList();
    }
    
    void ts3plugin_onUpdateClientEvent(uint64 serverConnectionHandlerID, anyID clientID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) {
    }
    
    void ts3plugin_onClientMoveEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, const char* moveMessage) {
    
    	getController(serverConnectionHandlerID)->updateClientList();
    
    	QString ClientName = clientID2Name(serverConnectionHandlerID, clientID);
    	QString oldChannel = channelID2Name(serverConnectionHandlerID, oldChannelID);
    	QString newChannel = channelID2Name(serverConnectionHandlerID, newChannelID);
    
    	anyID myID;
    	ts3Functions.getClientID(serverConnectionHandlerID, &myID);
    
    	if (!ClientName.isEmpty() && !oldChannel.isEmpty() && !newChannel.isEmpty())
    	{
    		// joined my channel
    		if (newChannelID == getCurrentChannel(serverConnectionHandlerID))
    			getController(serverConnectionHandlerID)->addChatLine(QString("<font color=\"#00FFFF\">%1 <font size=\"-5\">entered from</font> %2</font>").arg(ClientName.toHtmlEscaped()).arg(oldChannel));
    		// quit my channel
    		else if (oldChannelID == getCurrentChannel(serverConnectionHandlerID))
    			getController(serverConnectionHandlerID)->addChatLine(QString("<font color=\"#00FFFF\">%1 <font size=\"-5\">left to</font> %2</font>").arg(ClientName.toHtmlEscaped()).arg(newChannel));
    		// somewhere else
    		else
    			getController(serverConnectionHandlerID)->addChatLine(QString("<font size=\"-5\">%1 moved from %2 to %3</font>").arg(ClientName.toHtmlEscaped()).arg(oldChannel).arg(newChannel));
    	}
    	else if (!ClientName.isEmpty() && oldChannel.isEmpty() && !newChannel.isEmpty())
    	{
    		getController(serverConnectionHandlerID)->addChatLine(QString("%1 <font size=\"-5\">connected to</font> %2").arg(ClientName.toHtmlEscaped()).arg(newChannel));
    	}
    
    }
    
    void ts3plugin_onClientMoveSubscriptionEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility) {
    }
    
    void ts3plugin_onClientMoveTimeoutEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, const char* timeoutMessage) {
    
    }
    
    void ts3plugin_onClientMoveMovedEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID moverID, const char* moverName, const char* moverUniqueIdentifier, const char* moveMessage) {
    
    	getController(serverConnectionHandlerID)->updateClientList();
    
    	QString ClientName = clientID2Name(serverConnectionHandlerID, clientID);
    	QString oldChannel = channelID2Name(serverConnectionHandlerID, oldChannelID);
    	QString newChannel = channelID2Name(serverConnectionHandlerID, newChannelID);
    
    	anyID myID;
    	ts3Functions.getClientID(serverConnectionHandlerID, &myID);
    
    	if (!ClientName.isEmpty() && !oldChannel.isEmpty() && !newChannel.isEmpty())
    	{
    		// joined my channel
    		if (newChannelID == getCurrentChannel(serverConnectionHandlerID))
    			getController(serverConnectionHandlerID)->addChatLine(QString("<font color=\"#00FFFF\">%1 <font size=\"-5\">entered from</font> %2 <font size=\"-5\">by</font> %3</font>").arg(ClientName.toHtmlEscaped()).arg(oldChannel).arg(QString(moverName).toHtmlEscaped()));
    		// quit my channel
    		else if (oldChannelID == getCurrentChannel(serverConnectionHandlerID))
    			getController(serverConnectionHandlerID)->addChatLine(QString("<font color=\"#00FFFF\">%1 <font size=\"-5\">left to</font> %2 <font size=\"-5\">left by</font> %3</font>").arg(ClientName.toHtmlEscaped()).arg(newChannel).arg(QString(moverName).toHtmlEscaped()));
    		// somewhere else
    		else
    			getController(serverConnectionHandlerID)->addChatLine(QString("<font size=\"-5\">%1 moved from %2 to %3 by %4</font>").arg(ClientName.toHtmlEscaped()).arg(oldChannel).arg(newChannel).arg(QString(moverName).toHtmlEscaped()));
    	}
    }
    
    void ts3plugin_onClientKickFromChannelEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID kickerID, const char* kickerName, const char* kickerUniqueIdentifier, const char* kickMessage) {
    
    	getController(serverConnectionHandlerID)->updateClientList();
    
    	QString ClientName = clientID2Name(serverConnectionHandlerID, clientID);
    	QString oldChannel = channelID2Name(serverConnectionHandlerID, oldChannelID);
    	QString newChannel = channelID2Name(serverConnectionHandlerID, newChannelID);
    
    	if (!ClientName.isEmpty() && !oldChannel.isEmpty() && !newChannel.isEmpty())
    	{
    		getController(serverConnectionHandlerID)->addChatLine(QString("<font color=\"#FF0000\">%1 <font size=\"-5\">was from</font> %2 <font size=\"-5\">to</font> %3 <font size=\"-5\">by</font> %4 <font size=\"-5\">because</font> %5</font>").arg(ClientName.toHtmlEscaped()).arg(oldChannel).arg(newChannel).arg(QString(kickerName).toHtmlEscaped()).arg(kickMessage));
    	}
    }
    
    void ts3plugin_onClientKickFromServerEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID kickerID, const char* kickerName, const char* kickerUniqueIdentifier, const char* kickMessage) {
    
    	getController(serverConnectionHandlerID)->updateClientList();
    
    	QString ClientName = clientID2Name(serverConnectionHandlerID, clientID);
    
    	if (!ClientName.isEmpty())
    	{
    		getController(serverConnectionHandlerID)->addChatLine(QString("<font color=\"#FF0000\">%1 <font size=\"-5\">was from Server by</font> %2 <font size=\"-5\">because</font> %3</font>").arg(ClientName.toHtmlEscaped()).arg(QString(kickerName).toHtmlEscaped()).arg(kickMessage));
    	}
    }
    
    void ts3plugin_onClientIDsEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, anyID clientID, const char* clientName) {
    }
    
    void ts3plugin_onClientIDsFinishedEvent(uint64 serverConnectionHandlerID) {
    }
    
    void ts3plugin_onServerEditedEvent(uint64 serverConnectionHandlerID, anyID editerID, const char* editerName, const char* editerUniqueIdentifier) {
    }
    
    void ts3plugin_onServerUpdatedEvent(uint64 serverConnectionHandlerID) {
    }
    
    int ts3plugin_onServerErrorEvent(uint64 serverConnectionHandlerID, const char* errorMessage, unsigned int error, const char* returnCode, const char* extraMessage) {
    	return 0;  /* If no plugin return code was used, the return value of this function is ignored */
    }
    
    void ts3plugin_onServerStopEvent(uint64 serverConnectionHandlerID, const char* shutdownMessage) {
    }
    
    int ts3plugin_onTextMessageEvent(uint64 serverConnectionHandlerID, anyID targetMode, anyID toID, anyID fromID, const char* fromName, const char* fromUniqueIdentifier, const char* message, int ffIgnored) {
    	
    	getController(serverConnectionHandlerID)->addChatLine(QString("<font size=\"-5\">&lt;%1&gt;</font> %2").arg(QString(fromName).toHtmlEscaped()).arg(message));
    
    	return 0;  /* 0 = handle normally, 1 = client will ignore the text message */
    }
    
    void ts3plugin_onTalkStatusChangeEvent(uint64 serverConnectionHandlerID, int status, int isReceivedWhisper, anyID clientID) {
    
    	char name[512];
    	if (ts3Functions.getClientDisplayName(serverConnectionHandlerID, clientID, name, 512) == ERROR_ok)
    	{
    		if (status == STATUS_TALKING)
    			getController(serverConnectionHandlerID)->addSpeaker(name);
    		else
    			getController(serverConnectionHandlerID)->removeSpeaker(name);
    	}
    }
    
    void ts3plugin_onConnectionInfoEvent(uint64 serverConnectionHandlerID, anyID clientID) {
    }
    
    void ts3plugin_onServerConnectionInfoEvent(uint64 serverConnectionHandlerID) {
    }
    
    void ts3plugin_onChannelSubscribeEvent(uint64 serverConnectionHandlerID, uint64 channelID) {
    }
    
    void ts3plugin_onChannelSubscribeFinishedEvent(uint64 serverConnectionHandlerID) {
    	getController(serverConnectionHandlerID)->updateClientList();
    }
    
    void ts3plugin_onChannelUnsubscribeEvent(uint64 serverConnectionHandlerID, uint64 channelID) {
    }
    
    void ts3plugin_onChannelUnsubscribeFinishedEvent(uint64 serverConnectionHandlerID) {
    }
    
    void ts3plugin_onChannelDescriptionUpdateEvent(uint64 serverConnectionHandlerID, uint64 channelID) {
    }
    
    void ts3plugin_onChannelPasswordChangedEvent(uint64 serverConnectionHandlerID, uint64 channelID) {
    }
    
    void ts3plugin_onPlaybackShutdownCompleteEvent(uint64 serverConnectionHandlerID) {
    }
    
    void ts3plugin_onSoundDeviceListChangedEvent(const char* modeID, int playOrCap) {
    }
    
    void ts3plugin_onEditPlaybackVoiceDataEvent(uint64 serverConnectionHandlerID, anyID clientID, short* samples, int sampleCount, int channels) {
    }
    
    void ts3plugin_onEditPostProcessVoiceDataEvent(uint64 serverConnectionHandlerID, anyID clientID, short* samples, int sampleCount, int channels, const unsigned int* channelSpeakerArray, unsigned int* channelFillMask) {
    }
    
    void ts3plugin_onEditMixedPlaybackVoiceDataEvent(uint64 serverConnectionHandlerID, short* samples, int sampleCount, int channels, const unsigned int* channelSpeakerArray, unsigned int* channelFillMask) {
    }
    
    void ts3plugin_onEditCapturedVoiceDataEvent(uint64 serverConnectionHandlerID, short* samples, int sampleCount, int channels, int* edited) {
    }
    
    void ts3plugin_onCustom3dRolloffCalculationClientEvent(uint64 serverConnectionHandlerID, anyID clientID, float distance, float* volume) {
    }
    
    void ts3plugin_onCustom3dRolloffCalculationWaveEvent(uint64 serverConnectionHandlerID, uint64 waveHandle, float distance, float* volume) {
    }
    
    void ts3plugin_onUserLoggingMessageEvent(const char* logMessage, int logLevel, const char* logChannel, uint64 logID, const char* logTime, const char* completeLogString) {
    }
    
    #pragma endregion
    
    
    /* Clientlib rare */
    
    #pragma region callbacks clientlib rare
    
    void ts3plugin_onClientBanFromServerEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID kickerID, const char* kickerName, const char* kickerUniqueIdentifier, uint64 time, const char* kickMessage) {
    }
    
    int ts3plugin_onClientPokeEvent(uint64 serverConnectionHandlerID, anyID fromClientID, const char* pokerName, const char* pokerUniqueIdentity, const char* message, int ffIgnored) {
    	
    	getController(serverConnectionHandlerID)->addChatLine(QString("<font color=\"#00FF00\"><font size=\"-5\">%1</font> Wake up! %2</font>").arg(pokerName).arg(message));
    
    	return 0;  /* 0 = handle normally, 1 = client will ignore the poke */
    }
    
    void ts3plugin_onClientSelfVariableUpdateEvent(uint64 serverConnectionHandlerID, int flag, const char* oldValue, const char* newValue) {
    
    	if (flag == CLIENT_INPUT_HARDWARE)
    	{
    		// from mute to speak
    		if (atoi(oldValue) == 0 && atoi(newValue) == 1)
    			setActiveServer(serverConnectionHandlerID);
    		// this should not happen
    		else
    			getController(serverConnectionHandlerID)->debugPrint("This should not happen");
    	}
    }
    
    void ts3plugin_onFileListEvent(uint64 serverConnectionHandlerID, uint64 channelID, const char* path, const char* name, uint64 size, uint64 datetime, int type, uint64 incompletesize, const char* returnCode) {
    }
    
    void ts3plugin_onFileListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelID, const char* path) {
    }
    
    void ts3plugin_onFileInfoEvent(uint64 serverConnectionHandlerID, uint64 channelID, const char* name, uint64 size, uint64 datetime) {
    }
    
    void ts3plugin_onServerGroupListEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID, const char* name, int type, int iconID, int saveDB) {
    }
    
    void ts3plugin_onServerGroupListFinishedEvent(uint64 serverConnectionHandlerID) {
    }
    
    void ts3plugin_onServerGroupByClientIDEvent(uint64 serverConnectionHandlerID, const char* name, uint64 serverGroupList, uint64 clientDatabaseID) {
    }
    
    void ts3plugin_onServerGroupPermListEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) {
    }
    
    void ts3plugin_onServerGroupPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID) {
    }
    
    void ts3plugin_onServerGroupClientListEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID, uint64 clientDatabaseID, const char* clientNameIdentifier, const char* clientUniqueID) {
    }
    
    void ts3plugin_onChannelGroupListEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID, const char* name, int type, int iconID, int saveDB) {
    }
    
    void ts3plugin_onChannelGroupListFinishedEvent(uint64 serverConnectionHandlerID) {
    }
    
    void ts3plugin_onChannelGroupPermListEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) {
    }
    
    void ts3plugin_onChannelGroupPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID) {
    }
    
    void ts3plugin_onChannelPermListEvent(uint64 serverConnectionHandlerID, uint64 channelID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) {
    }
    
    void ts3plugin_onChannelPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelID) {
    }
    
    void ts3plugin_onClientPermListEvent(uint64 serverConnectionHandlerID, uint64 clientDatabaseID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) {
    }
    
    void ts3plugin_onClientPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 clientDatabaseID) {
    }
    
    void ts3plugin_onChannelClientPermListEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 clientDatabaseID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) {
    }
    
    void ts3plugin_onChannelClientPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 clientDatabaseID) {
    }
    
    void ts3plugin_onClientChannelGroupChangedEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID, uint64 channelID, anyID clientID, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity) {
    }
    
    int ts3plugin_onServerPermissionErrorEvent(uint64 serverConnectionHandlerID, const char* errorMessage, unsigned int error, const char* returnCode, unsigned int failedPermissionID) {
    	return 0;  /* See onServerErrorEvent for return code description */
    }
    
    void ts3plugin_onPermissionListGroupEndIDEvent(uint64 serverConnectionHandlerID, unsigned int groupEndID) {
    }
    
    void ts3plugin_onPermissionListEvent(uint64 serverConnectionHandlerID, unsigned int permissionID, const char* permissionName, const char* permissionDescription) {
    }
    
    void ts3plugin_onPermissionListFinishedEvent(uint64 serverConnectionHandlerID) {
    }
    
    void ts3plugin_onPermissionOverviewEvent(uint64 serverConnectionHandlerID, uint64 clientDatabaseID, uint64 channelID, int overviewType, uint64 overviewID1, uint64 overviewID2, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) {
    }
    
    void ts3plugin_onPermissionOverviewFinishedEvent(uint64 serverConnectionHandlerID) {
    }
    
    void ts3plugin_onServerGroupClientAddedEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientName, const char* clientUniqueIdentity, uint64 serverGroupID, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity) {
    }
    
    void ts3plugin_onServerGroupClientDeletedEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientName, const char* clientUniqueIdentity, uint64 serverGroupID, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity) {
    }
    
    void ts3plugin_onClientNeededPermissionsEvent(uint64 serverConnectionHandlerID, unsigned int permissionID, int permissionValue) {
    }
    
    void ts3plugin_onClientNeededPermissionsFinishedEvent(uint64 serverConnectionHandlerID) {
    }
    
    void ts3plugin_onFileTransferStatusEvent(anyID transferID, unsigned int status, const char* statusMessage, uint64 remotefileSize, uint64 serverConnectionHandlerID) {
    }
    
    void ts3plugin_onClientChatClosedEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientUniqueIdentity) {
    }
    
    void ts3plugin_onClientChatComposingEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientUniqueIdentity) {
    }
    
    void ts3plugin_onServerLogEvent(uint64 serverConnectionHandlerID, const char* logMsg) {
    }
    
    void ts3plugin_onServerLogFinishedEvent(uint64 serverConnectionHandlerID, uint64 lastPos, uint64 fileSize) {
    }
    
    void ts3plugin_onMessageListEvent(uint64 serverConnectionHandlerID, uint64 messageID, const char* fromClientUniqueIdentity, const char* subject, uint64 timestamp, int flagRead) {
    }
    
    void ts3plugin_onMessageGetEvent(uint64 serverConnectionHandlerID, uint64 messageID, const char* fromClientUniqueIdentity, const char* subject, const char* message, uint64 timestamp) {
    }
    
    void ts3plugin_onClientDBIDfromUIDEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, uint64 clientDatabaseID) {
    }
    
    void ts3plugin_onClientNamefromUIDEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, uint64 clientDatabaseID, const char* clientNickName) {
    }
    
    void ts3plugin_onClientNamefromDBIDEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, uint64 clientDatabaseID, const char* clientNickName) {
    }
    
    void ts3plugin_onComplainListEvent(uint64 serverConnectionHandlerID, uint64 targetClientDatabaseID, const char* targetClientNickName, uint64 fromClientDatabaseID, const char* fromClientNickName, const char* complainReason, uint64 timestamp) {
    }
    
    void ts3plugin_onBanListEvent(uint64 serverConnectionHandlerID, uint64 banid, const char* ip, const char* name, const char* uid, uint64 creationTime, uint64 durationTime, const char* invokerName,
    	uint64 invokercldbid, const char* invokeruid, const char* reason, int numberOfEnforcements, const char* lastNickName) {
    }
    
    void ts3plugin_onClientServerQueryLoginPasswordEvent(uint64 serverConnectionHandlerID, const char* loginPassword) {
    }
    
    void ts3plugin_onPluginCommandEvent(uint64 serverConnectionHandlerID, const char* pluginName, const char* pluginCommand) {
    }
    
    void ts3plugin_onIncomingClientQueryEvent(uint64 serverConnectionHandlerID, const char* commandText) {
    }
    
    void ts3plugin_onServerTemporaryPasswordListEvent(uint64 serverConnectionHandlerID, const char* clientNickname, const char* uniqueClientIdentifier, const char* description, const char* password, uint64 timestampStart, uint64 timestampEnd, uint64 targetChannelID, const char* targetChannelPW) {
    }
    
    #pragma endregion
    
    
    /* Client UI callbacks */
    
    #pragma region callbacks client UI
    
    /*
    * Called from client when an avatar image has been downloaded to or deleted from cache.
    * This callback can be called spontaneously or in response to ts3Functions.getAvatar()
    */
    void ts3plugin_onAvatarUpdated(uint64 serverConnectionHandlerID, anyID clientID, const char* avatarPath) {
    }
    
    /*
    * Called when a plugin menu item (see ts3plugin_initMenus) is triggered. Optional function, when not using plugin menus, do not implement this.
    *
    * Parameters:
    * - serverConnectionHandlerID: ID of the current server tab
    * - type: Type of the menu (PLUGIN_MENU_TYPE_CHANNEL, PLUGIN_MENU_TYPE_CLIENT or PLUGIN_MENU_TYPE_GLOBAL)
    * - menuItemID: Id used when creating the menu item
    * - selectedItemID: Channel or Client ID in the case of PLUGIN_MENU_TYPE_CHANNEL and PLUGIN_MENU_TYPE_CLIENT. 0 for PLUGIN_MENU_TYPE_GLOBAL.
    */
    void ts3plugin_onMenuItemEvent(uint64 serverConnectionHandlerID, enum PluginMenuType type, int menuItemID, uint64 selectedItemID) {
    }
    
    /* This function is called if a plugin hotkey was pressed. Omit if hotkeys are unused. */
    void ts3plugin_onHotkeyEvent(const char* keyword) {
    	printf("PLUGIN: Hotkey event: %s\n", keyword);
    
    	if (QString(keyword) == "Channellist")
    	{
    		auto controller = getController();
    		if (controller != NULL)
    		{
    			controller->displayChannelList();
    		}
    	}
    }
    
    /* Called when recording a hotkey has finished after calling ts3Functions.requestHotkeyInputDialog */
    void ts3plugin_onHotkeyRecordedEvent(const char* keyword, const char* key) {
    }
    
    /* Called when client custom nickname changed */
    void ts3plugin_onClientDisplayNameChanged(uint64 serverConnectionHandlerID, anyID clientID, const char* displayName, const char* uniqueClientIdentifier) {
    }
    
    #pragma endregion