diff --git a/.gitignore b/.gitignore index e276a4b..4678142 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -<<<<<<< HEAD +build-* + # ---> C++ # Prerequisites *.d @@ -32,7 +33,6 @@ *.exe *.out *.app -======= ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## diff --git a/TS_WIFILED.pro b/TS_WIFILED.pro index 056aabc..cd6b86c 100644 --- a/TS_WIFILED.pro +++ b/TS_WIFILED.pro @@ -4,6 +4,8 @@ #TARGET = TS_WIFILED TEMPLATE = lib +QT += core network +CONFIG += c++14 HEADERS = \ $$PWD/include/teamlog/logtypes.h \ @@ -14,10 +16,12 @@ HEADERS = \ $$PWD/include/teamspeak/public_rare_definitions.h \ $$PWD/include/plugin_definitions.h \ $$PWD/include/ts3_functions.h \ - $$PWD/src/plugin.h + $$PWD/src/plugin.h \ \ + src/ledhandler.h SOURCES = \ - $$PWD/src/plugin.c + $$PWD/src/plugin.cpp \ + src/ledhandler.cpp INCLUDEPATH = \ $$PWD/include \ diff --git a/src/ledhandler.cpp b/src/ledhandler.cpp new file mode 100644 index 0000000..3a4ace4 --- /dev/null +++ b/src/ledhandler.cpp @@ -0,0 +1,59 @@ +#include "ledhandler.h" + +LEDHandler::LEDHandler(QUdpSocket* sock, TS3Functions ts3Functions) +{ + mSock = sock; + mTs3Functions = ts3Functions; + + connect(mSock, &QUdpSocket::connected, this, &LEDHandler::connected); + connect(mSock, &QUdpSocket::disconnected, this, &LEDHandler::disconnected); + connect(mSock, &QUdpSocket::hostFound, this, &LEDHandler::hostFound); +} + +void LEDHandler::talkingStarted() +{ + printf("started\n"); + sendColor(0, 0, 255, 255, 255); +} + +void LEDHandler::talkingEnded() +{ + printf("stopped\n"); + sendColor(0, 0, 0, 0, 0); +} + +void LEDHandler::sendColor(int R, int G, int B, int W, int t) +{ + QByteArray msg; + msg[0] = 3; // protocol: DRGBW + msg[1] = t; // timeout + msg[2] = R; // R + msg[2] = B; // G + msg[2] = G; // B + msg[2] = W; // W + + mSock->write(msg); +} + +void LEDHandler::connected() +{ + mTs3Functions.logMessage("CONNECTED", LogLevel_INFO, "Plugin", 0); + printf("CONNECTED\n"); +} + +void LEDHandler::disconnected() +{ + mTs3Functions.logMessage("DISCONNECTED", LogLevel_INFO, "Plugin", 0); + printf("DISCONNECTED\n"); +} + +void LEDHandler::hostFound() +{ + mTs3Functions.logMessage("HOST FOUND", LogLevel_INFO, "Plugin", 0); + printf("HOST FOUND\n"); +} + +//const char* LED_URL_SAVE = "http://10.0.0.222/win&PS=16&NN"; +//const char* LED_URL_ON = "http://10.0.0.222/win&T=1&FX=0&R=0&B=255&G=0&W=0&A=255&NN"; +//const char* LED_URL_OFF= "http://10.0.0.222/win&PL=16&NN"; +//const char* LED_URL_POKE = "http://10.0.0.222/win&PL=15&NN"; diff --git a/src/ledhandler.h b/src/ledhandler.h new file mode 100644 index 0000000..5b36241 --- /dev/null +++ b/src/ledhandler.h @@ -0,0 +1,30 @@ +#ifndef LEDHANDLER_H +#define LEDHANDLER_H + +#include +#include + + +class LEDHandler : public QObject +{ +public: + QString cURL = "10.0.0.222"; + int cPORT = 21324; + + LEDHandler(QUdpSocket* sock, TS3Functions ts3Functions); + + void talkingEnded(); + void talkingStarted(); + +public slots: + void connected(); + void disconnected(); + void hostFound(); + +private: + QUdpSocket* mSock; + TS3Functions mTs3Functions; + void sendColor(int R, int G, int B, int W, int t); +}; + +#endif // LEDHANDLER_H diff --git a/src/plugin.c b/src/plugin.cpp similarity index 56% rename from src/plugin.c rename to src/plugin.cpp index 887f3b0..9af4455 100644 --- a/src/plugin.c +++ b/src/plugin.cpp @@ -3,32 +3,22 @@ * * Copyright (c) TeamSpeak Systems GmbH */ -#define CURL_STATICLIB -# + #if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) #pragma warning (disable : 4100) /* Disable Unreferenced parameter warning */ #include #endif -#include -#include -#include -#include +#include +#include + +#include "plugin.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 "curl/curl.h" - -//#pragma comment (lib, "curl/libcurl_a.lib") -#pragma comment (lib, "Normaliz.lib") -#pragma comment (lib, "Ws2_32.lib") -#pragma comment (lib, "Wldap32.lib") -#pragma comment (lib, "Crypt32.lib") -#pragma comment (lib, "advapi32.lib") static struct TS3Functions ts3Functions; @@ -49,28 +39,10 @@ static struct TS3Functions ts3Functions; #define RETURNCODE_BUFSIZE 128 static char* pluginID = NULL; -//CURL* curl; -//CURLcode res; -const char* LED_URL_SAVE = "http://10.0.0.222/win&PS=16&NN"; -const char* LED_URL_ON = "http://10.0.0.222/win&T=1&FX=0&R=0&B=255&G=0&W=0&A=255&NN"; -const char* LED_URL_OFF= "http://10.0.0.222/win&PL=16&NN"; -const char* LED_URL_POKE = "http://10.0.0.222/win&PL=15&NN"; + anyID myClientID = 0; -#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 - /*********************************** Required functions ************************************/ /* * If any of these required functions is not implemented, TS3 will refuse to load the plugin @@ -78,41 +50,30 @@ static int wcharToUtf8(const wchar_t* str, char** result) { /* 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"WIFILED"; - if(wcharToUtf8(name, &result) == -1) { /* Convert name into UTF-8 encoded result */ - result = "WIFILED"; /* Conversion failed, fallback here */ - } - } - return result; -#else - return "WIFILED"; -#endif + + return "WIFILED"; } /* Plugin version */ const char* ts3plugin_version() { - return "0.1"; + return "0.4"; } /* 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; + return PLUGIN_API_VERSION; } /* Plugin author */ const char* ts3plugin_author() { - /* If you want to use wchar_t, see ts3plugin_name() on how to use */ + /* If you want to use wchar_t, see ts3plugin_name() on how to use */ return "Rogosoftware"; } /* Plugin description */ const char* ts3plugin_description() { - /* If you want to use wchar_t, see ts3plugin_name() on how to use */ - return "This plugin sends HTTP Requests to an WLED Server to light LEDs."; + /* If you want to use wchar_t, see ts3plugin_name() on how to use */ + return "This plugin sends UDP packets to an WLED Server to light LEDs."; } /* Set TeamSpeak 3 callback functions */ @@ -128,7 +89,7 @@ int ts3plugin_init() { char appPath[PATH_BUFSIZE]; char resourcesPath[PATH_BUFSIZE]; char configPath[PATH_BUFSIZE]; - char pluginPath[PATH_BUFSIZE]; + char pluginPath[PATH_BUFSIZE]; /* Your plugin init code here */ printf("PLUGIN: init\n"); @@ -138,38 +99,41 @@ int ts3plugin_init() { ts3Functions.getAppPath(appPath, PATH_BUFSIZE); ts3Functions.getResourcesPath(resourcesPath, PATH_BUFSIZE); ts3Functions.getConfigPath(configPath, PATH_BUFSIZE); - ts3Functions.getPluginPath(pluginPath, PATH_BUFSIZE, pluginID); + ts3Functions.getPluginPath(pluginPath, PATH_BUFSIZE, pluginID); - printf("PLUGIN: App path: %s\nResources path: %s\nConfig path: %s\nPlugin path: %s\n", appPath, resourcesPath, configPath, pluginPath); + printf("PLUGIN: App path: %s\nResources path: %s\nConfig path: %s\nPlugin path: %s\n", appPath, resourcesPath, configPath, pluginPath); -// curl_global_init(CURL_GLOBAL_ALL); -// curl = curl_easy_init(); + mUdpSock = new QUdpSocket(); + mLedHandler = new LEDHandler(mUdpSock, ts3Functions); + + mUdpSock->connectToHost(mLedHandler->cURL, mLedHandler->cPORT, QIODevice::WriteOnly); 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. */ + /* -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() { /* Your plugin cleanup code here */ printf("PLUGIN: shutdown\n"); - -// curl_easy_cleanup(curl); -// curl_global_cleanup(); - /* - * 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). - */ - /* Free pluginID if we registered it */ - if(pluginID) { - free(pluginID); - pluginID = NULL; - } + delete mUdpSock; + delete mLedHandler; + + /* + * 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). + */ + + /* Free pluginID if we registered it */ + if(pluginID) { + free(pluginID); + pluginID = NULL; + } } /****************************** Optional functions ********************************/ @@ -179,14 +143,14 @@ void ts3plugin_shutdown() { /* 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() { - printf("PLUGIN: offersConfigure\n"); - /* - * 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 */ + printf("PLUGIN: offersConfigure\n"); + /* + * 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. */ @@ -200,15 +164,15 @@ void ts3plugin_configure(void* handle, void* qParentWidget) { * 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); /* The id buffer will invalidate after exiting this function */ - printf("PLUGIN: registerPluginID: %s\n", pluginID); + const size_t sz = strlen(id) + 1; + pluginID = (char*)malloc(sz * sizeof(char)); + _strcpy(pluginID, sz, id); /* The id buffer will invalidate after exiting this function */ + printf("PLUGIN: registerPluginID: %s\n", pluginID); } /* Plugin command keyword. Return NULL or "" if not used. */ const char* ts3plugin_commandKeyword() { - return "LED"; + return "LED"; } static void print_and_free_bookmarks_list(struct PluginBookmarkList* list) @@ -230,231 +194,231 @@ static void print_and_free_bookmarks_list(struct PluginBookmarkList* list) /* Plugin processes console command. Return 0 if plugin handled the command, 1 if not handled. */ int ts3plugin_processCommand(uint64 serverConnectionHandlerID, const char* command) { - char buf[COMMAND_BUFSIZE]; - char *s, *param1 = NULL, *param2 = NULL; - int i = 0; - enum { CMD_NONE = 0, CMD_JOIN, CMD_COMMAND, CMD_SERVERINFO, CMD_CHANNELINFO, CMD_AVATAR, CMD_ENABLEMENU, CMD_SUBSCRIBE, CMD_UNSUBSCRIBE, CMD_SUBSCRIBEALL, CMD_UNSUBSCRIBEALL, CMD_BOOKMARKSLIST } cmd = CMD_NONE; + char buf[COMMAND_BUFSIZE]; + char *s, *param1 = NULL, *param2 = NULL; + int i = 0; + enum { CMD_NONE = 0, CMD_JOIN, CMD_COMMAND, CMD_SERVERINFO, CMD_CHANNELINFO, CMD_AVATAR, CMD_ENABLEMENU, CMD_SUBSCRIBE, CMD_UNSUBSCRIBE, CMD_SUBSCRIBEALL, CMD_UNSUBSCRIBEALL, CMD_BOOKMARKSLIST } cmd = CMD_NONE; #ifdef _WIN32 - char* context = NULL; + char* context = NULL; #endif - printf("PLUGIN: process command: '%s'\n", command); + printf("PLUGIN: process command: '%s'\n", command); - _strcpy(buf, COMMAND_BUFSIZE, command); + _strcpy(buf, COMMAND_BUFSIZE, command); #ifdef _WIN32 - s = strtok_s(buf, " ", &context); + s = strtok_s(buf, " ", &context); #else - s = strtok(buf, " "); + s = strtok(buf, " "); #endif - while(s != NULL) { - if(i == 0) { - if(!strcmp(s, "join")) { - cmd = CMD_JOIN; - } else if(!strcmp(s, "command")) { - cmd = CMD_COMMAND; - } else if(!strcmp(s, "serverinfo")) { - cmd = CMD_SERVERINFO; - } else if(!strcmp(s, "channelinfo")) { - cmd = CMD_CHANNELINFO; - } else if(!strcmp(s, "avatar")) { - cmd = CMD_AVATAR; - } else if(!strcmp(s, "enablemenu")) { - cmd = CMD_ENABLEMENU; - } else if(!strcmp(s, "subscribe")) { - cmd = CMD_SUBSCRIBE; - } else if(!strcmp(s, "unsubscribe")) { - cmd = CMD_UNSUBSCRIBE; - } else if(!strcmp(s, "subscribeall")) { - cmd = CMD_SUBSCRIBEALL; - } else if(!strcmp(s, "unsubscribeall")) { - cmd = CMD_UNSUBSCRIBEALL; + while(s != NULL) { + if(i == 0) { + if(!strcmp(s, "join")) { + cmd = CMD_JOIN; + } else if(!strcmp(s, "command")) { + cmd = CMD_COMMAND; + } else if(!strcmp(s, "serverinfo")) { + cmd = CMD_SERVERINFO; + } else if(!strcmp(s, "channelinfo")) { + cmd = CMD_CHANNELINFO; + } else if(!strcmp(s, "avatar")) { + cmd = CMD_AVATAR; + } else if(!strcmp(s, "enablemenu")) { + cmd = CMD_ENABLEMENU; + } else if(!strcmp(s, "subscribe")) { + cmd = CMD_SUBSCRIBE; + } else if(!strcmp(s, "unsubscribe")) { + cmd = CMD_UNSUBSCRIBE; + } else if(!strcmp(s, "subscribeall")) { + cmd = CMD_SUBSCRIBEALL; + } else if(!strcmp(s, "unsubscribeall")) { + cmd = CMD_UNSUBSCRIBEALL; } else if (!strcmp(s, "bookmarkslist")) { cmd = CMD_BOOKMARKSLIST; } - } else if(i == 1) { - param1 = s; - } else { - param2 = s; - } + } else if(i == 1) { + param1 = s; + } else { + param2 = s; + } #ifdef _WIN32 - s = strtok_s(NULL, " ", &context); + s = strtok_s(NULL, " ", &context); #else - s = strtok(NULL, " "); + s = strtok(NULL, " "); #endif - i++; - } + i++; + } - switch(cmd) { - case CMD_NONE: - return 1; /* Command not handled by plugin */ - case CMD_JOIN: /* /test join [optionalCannelPassword] */ - if(param1) { - uint64 channelID = (uint64)atoi(param1); - char* password = param2 ? param2 : ""; - char returnCode[RETURNCODE_BUFSIZE]; - anyID myID; + switch(cmd) { + case CMD_NONE: + return 1; /* Command not handled by plugin */ + case CMD_JOIN: /* /test join [optionalCannelPassword] */ + if(param1) { + uint64 channelID = (uint64)atoi(param1); + const char* password = param2 ? param2 : ""; + char returnCode[RETURNCODE_BUFSIZE]; + anyID myID; - /* Get own clientID */ - if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) { - ts3Functions.logMessage("Error querying client ID", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - break; - } + /* Get own clientID */ + if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) { + ts3Functions.logMessage("Error querying client ID", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); + break; + } - /* Create return code for requestClientMove function call. If creation fails, returnCode will be NULL, which can be - * passed into the client functions meaning no return code is used. - * Note: To use return codes, the plugin needs to register a plugin ID using ts3plugin_registerPluginID */ - ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); + /* Create return code for requestClientMove function call. If creation fails, returnCode will be NULL, which can be + * passed into the client functions meaning no return code is used. + * Note: To use return codes, the plugin needs to register a plugin ID using ts3plugin_registerPluginID */ + ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); - /* In a real world plugin, the returnCode should be remembered (e.g. in a dynamic STL vector, if it's a C++ plugin). - * onServerErrorEvent can then check the received returnCode, compare with the remembered ones and thus identify - * which function call has triggered the event and react accordingly. */ + /* In a real world plugin, the returnCode should be remembered (e.g. in a dynamic STL vector, if it's a C++ plugin). + * onServerErrorEvent can then check the received returnCode, compare with the remembered ones and thus identify + * which function call has triggered the event and react accordingly. */ - /* Request joining specified channel using above created return code */ - if(ts3Functions.requestClientMove(serverConnectionHandlerID, myID, channelID, password, returnCode) != ERROR_ok) { - ts3Functions.logMessage("Error requesting client move", LogLevel_INFO, "Plugin", serverConnectionHandlerID); - } - } else { - ts3Functions.printMessageToCurrentTab("Missing channel ID parameter."); - } - break; - case CMD_COMMAND: /* /test command */ - if(param1) { - /* Send plugin command to all clients in current channel. In this case targetIds is unused and can be NULL. */ - if(pluginID) { - /* See ts3plugin_registerPluginID for how to obtain a pluginID */ - printf("PLUGIN: Sending plugin command to current channel: %s\n", param1); - ts3Functions.sendPluginCommand(serverConnectionHandlerID, pluginID, param1, PluginCommandTarget_CURRENT_CHANNEL, NULL, NULL); - } else { - printf("PLUGIN: Failed to send plugin command, was not registered.\n"); - } - } else { - ts3Functions.printMessageToCurrentTab("Missing command parameter."); - } - break; - case CMD_SERVERINFO: { /* /test serverinfo */ - /* Query host, port and server password of current server tab. - * The password parameter can be NULL if the plugin does not want to receive the server password. - * Note: Server password is only available if the user has actually used it when connecting. If a user has - * connected with the permission to ignore passwords (b_virtualserver_join_ignore_password) and the password, - * was not entered, it will not be available. - * getServerConnectInfo returns 0 on success, 1 on error or if current server tab is disconnected. */ - char host[SERVERINFO_BUFSIZE]; - /*char password[SERVERINFO_BUFSIZE];*/ - char* password = NULL; /* Don't receive server password */ - unsigned short port; - if(!ts3Functions.getServerConnectInfo(serverConnectionHandlerID, host, &port, password, SERVERINFO_BUFSIZE)) { - char msg[SERVERINFO_BUFSIZE]; - snprintf(msg, sizeof(msg), "Server Connect Info: %s:%d", host, port); - ts3Functions.printMessageToCurrentTab(msg); - } else { - ts3Functions.printMessageToCurrentTab("No server connect info available."); - } - break; - } - case CMD_CHANNELINFO: { /* /test channelinfo */ - /* Query channel path and password of current server tab. - * The password parameter can be NULL if the plugin does not want to receive the channel password. - * Note: Channel password is only available if the user has actually used it when entering the channel. If a user has - * entered a channel with the permission to ignore passwords (b_channel_join_ignore_password) and the password, - * was not entered, it will not be available. - * getChannelConnectInfo returns 0 on success, 1 on error or if current server tab is disconnected. */ - char path[CHANNELINFO_BUFSIZE]; - /*char password[CHANNELINFO_BUFSIZE];*/ - char* password = NULL; /* Don't receive channel password */ + /* Request joining specified channel using above created return code */ + if(ts3Functions.requestClientMove(serverConnectionHandlerID, myID, channelID, password, returnCode) != ERROR_ok) { + ts3Functions.logMessage("Error requesting client move", LogLevel_INFO, "Plugin", serverConnectionHandlerID); + } + } else { + ts3Functions.printMessageToCurrentTab("Missing channel ID parameter."); + } + break; + case CMD_COMMAND: /* /test command */ + if(param1) { + /* Send plugin command to all clients in current channel. In this case targetIds is unused and can be NULL. */ + if(pluginID) { + /* See ts3plugin_registerPluginID for how to obtain a pluginID */ + printf("PLUGIN: Sending plugin command to current channel: %s\n", param1); + ts3Functions.sendPluginCommand(serverConnectionHandlerID, pluginID, param1, PluginCommandTarget_CURRENT_CHANNEL, NULL, NULL); + } else { + printf("PLUGIN: Failed to send plugin command, was not registered.\n"); + } + } else { + ts3Functions.printMessageToCurrentTab("Missing command parameter."); + } + break; + case CMD_SERVERINFO: { /* /test serverinfo */ + /* Query host, port and server password of current server tab. + * The password parameter can be NULL if the plugin does not want to receive the server password. + * Note: Server password is only available if the user has actually used it when connecting. If a user has + * connected with the permission to ignore passwords (b_virtualserver_join_ignore_password) and the password, + * was not entered, it will not be available. + * getServerConnectInfo returns 0 on success, 1 on error or if current server tab is disconnected. */ + char host[SERVERINFO_BUFSIZE]; + /*char password[SERVERINFO_BUFSIZE];*/ + char* password = NULL; /* Don't receive server password */ + unsigned short port; + if(!ts3Functions.getServerConnectInfo(serverConnectionHandlerID, host, &port, password, SERVERINFO_BUFSIZE)) { + char msg[SERVERINFO_BUFSIZE]; + snprintf(msg, sizeof(msg), "Server Connect Info: %s:%d", host, port); + ts3Functions.printMessageToCurrentTab(msg); + } else { + ts3Functions.printMessageToCurrentTab("No server connect info available."); + } + break; + } + case CMD_CHANNELINFO: { /* /test channelinfo */ + /* Query channel path and password of current server tab. + * The password parameter can be NULL if the plugin does not want to receive the channel password. + * Note: Channel password is only available if the user has actually used it when entering the channel. If a user has + * entered a channel with the permission to ignore passwords (b_channel_join_ignore_password) and the password, + * was not entered, it will not be available. + * getChannelConnectInfo returns 0 on success, 1 on error or if current server tab is disconnected. */ + char path[CHANNELINFO_BUFSIZE]; + /*char password[CHANNELINFO_BUFSIZE];*/ + char* password = NULL; /* Don't receive channel password */ - /* Get own clientID and channelID */ - anyID myID; - uint64 myChannelID; - if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) { - ts3Functions.logMessage("Error querying client ID", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - break; - } - /* Get own channel ID */ - if(ts3Functions.getChannelOfClient(serverConnectionHandlerID, myID, &myChannelID) != ERROR_ok) { - ts3Functions.logMessage("Error querying channel ID", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - break; - } + /* Get own clientID and channelID */ + anyID myID; + uint64 myChannelID; + if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) { + ts3Functions.logMessage("Error querying client ID", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); + break; + } + /* Get own channel ID */ + if(ts3Functions.getChannelOfClient(serverConnectionHandlerID, myID, &myChannelID) != ERROR_ok) { + ts3Functions.logMessage("Error querying channel ID", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); + break; + } - /* Get channel connect info of own channel */ - if(!ts3Functions.getChannelConnectInfo(serverConnectionHandlerID, myChannelID, path, password, CHANNELINFO_BUFSIZE)) { - char msg[CHANNELINFO_BUFSIZE]; - snprintf(msg, sizeof(msg), "Channel Connect Info: %s", path); - ts3Functions.printMessageToCurrentTab(msg); - } else { - ts3Functions.printMessageToCurrentTab("No channel connect info available."); - } - break; - } - case CMD_AVATAR: { /* /test avatar */ - char avatarPath[PATH_BUFSIZE]; - anyID clientID = (anyID)atoi(param1); - unsigned int error; + /* Get channel connect info of own channel */ + if(!ts3Functions.getChannelConnectInfo(serverConnectionHandlerID, myChannelID, path, password, CHANNELINFO_BUFSIZE)) { + char msg[CHANNELINFO_BUFSIZE]; + snprintf(msg, sizeof(msg), "Channel Connect Info: %s", path); + ts3Functions.printMessageToCurrentTab(msg); + } else { + ts3Functions.printMessageToCurrentTab("No channel connect info available."); + } + break; + } + case CMD_AVATAR: { /* /test avatar */ + char avatarPath[PATH_BUFSIZE]; + anyID clientID = (anyID)atoi(param1); + unsigned int error; - memset(avatarPath, 0, PATH_BUFSIZE); - error = ts3Functions.getAvatar(serverConnectionHandlerID, clientID, avatarPath, PATH_BUFSIZE); - if(error == ERROR_ok) { /* ERROR_ok means the client has an avatar set. */ - if(strlen(avatarPath)) { /* Avatar path contains the full path to the avatar image in the TS3Client cache directory */ - printf("Avatar path: %s\n", avatarPath); - } else { /* Empty avatar path means the client has an avatar but the image has not yet been cached. The TeamSpeak - * client will automatically start the download and call onAvatarUpdated when done */ - printf("Avatar not yet downloaded, waiting for onAvatarUpdated...\n"); - } - } else if(error == ERROR_database_empty_result) { /* Not an error, the client simply has no avatar set */ - printf("Client has no avatar\n"); - } else { /* Other error occured (invalid server connection handler ID, invalid client ID, file io error etc) */ - printf("Error getting avatar: %d\n", error); - } - break; - } - case CMD_ENABLEMENU: /* /test enablemenu <0|1> */ - if(param1) { - int menuID = atoi(param1); - int enable = param2 ? atoi(param2) : 0; - ts3Functions.setPluginMenuEnabled(pluginID, menuID, enable); - } else { - ts3Functions.printMessageToCurrentTab("Usage is: /test enablemenu <0|1>"); - } - break; - case CMD_SUBSCRIBE: /* /test subscribe */ - if(param1) { - char returnCode[RETURNCODE_BUFSIZE]; - uint64 channelIDArray[2]; - channelIDArray[0] = (uint64)atoi(param1); - channelIDArray[1] = 0; - ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); - if(ts3Functions.requestChannelSubscribe(serverConnectionHandlerID, channelIDArray, returnCode) != ERROR_ok) { - ts3Functions.logMessage("Error subscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID); - } - } - break; - case CMD_UNSUBSCRIBE: /* /test unsubscribe */ - if(param1) { - char returnCode[RETURNCODE_BUFSIZE]; - uint64 channelIDArray[2]; - channelIDArray[0] = (uint64)atoi(param1); - channelIDArray[1] = 0; - ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); - if(ts3Functions.requestChannelUnsubscribe(serverConnectionHandlerID, channelIDArray, NULL) != ERROR_ok) { - ts3Functions.logMessage("Error unsubscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID); - } - } - break; - case CMD_SUBSCRIBEALL: { /* /test subscribeall */ - char returnCode[RETURNCODE_BUFSIZE]; - ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); - if(ts3Functions.requestChannelSubscribeAll(serverConnectionHandlerID, returnCode) != ERROR_ok) { - ts3Functions.logMessage("Error subscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID); - } - break; - } - case CMD_UNSUBSCRIBEALL: { /* /test unsubscribeall */ - char returnCode[RETURNCODE_BUFSIZE]; - ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); - if(ts3Functions.requestChannelUnsubscribeAll(serverConnectionHandlerID, returnCode) != ERROR_ok) { - ts3Functions.logMessage("Error subscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID); - } - break; - } + memset(avatarPath, 0, PATH_BUFSIZE); + error = ts3Functions.getAvatar(serverConnectionHandlerID, clientID, avatarPath, PATH_BUFSIZE); + if(error == ERROR_ok) { /* ERROR_ok means the client has an avatar set. */ + if(strlen(avatarPath)) { /* Avatar path contains the full path to the avatar image in the TS3Client cache directory */ + printf("Avatar path: %s\n", avatarPath); + } else { /* Empty avatar path means the client has an avatar but the image has not yet been cached. The TeamSpeak + * client will automatically start the download and call onAvatarUpdated when done */ + printf("Avatar not yet downloaded, waiting for onAvatarUpdated...\n"); + } + } else if(error == ERROR_database_empty_result) { /* Not an error, the client simply has no avatar set */ + printf("Client has no avatar\n"); + } else { /* Other error occured (invalid server connection handler ID, invalid client ID, file io error etc) */ + printf("Error getting avatar: %d\n", error); + } + break; + } + case CMD_ENABLEMENU: /* /test enablemenu <0|1> */ + if(param1) { + int menuID = atoi(param1); + int enable = param2 ? atoi(param2) : 0; + ts3Functions.setPluginMenuEnabled(pluginID, menuID, enable); + } else { + ts3Functions.printMessageToCurrentTab("Usage is: /test enablemenu <0|1>"); + } + break; + case CMD_SUBSCRIBE: /* /test subscribe */ + if(param1) { + char returnCode[RETURNCODE_BUFSIZE]; + uint64 channelIDArray[2]; + channelIDArray[0] = (uint64)atoi(param1); + channelIDArray[1] = 0; + ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); + if(ts3Functions.requestChannelSubscribe(serverConnectionHandlerID, channelIDArray, returnCode) != ERROR_ok) { + ts3Functions.logMessage("Error subscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID); + } + } + break; + case CMD_UNSUBSCRIBE: /* /test unsubscribe */ + if(param1) { + char returnCode[RETURNCODE_BUFSIZE]; + uint64 channelIDArray[2]; + channelIDArray[0] = (uint64)atoi(param1); + channelIDArray[1] = 0; + ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); + if(ts3Functions.requestChannelUnsubscribe(serverConnectionHandlerID, channelIDArray, NULL) != ERROR_ok) { + ts3Functions.logMessage("Error unsubscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID); + } + } + break; + case CMD_SUBSCRIBEALL: { /* /test subscribeall */ + char returnCode[RETURNCODE_BUFSIZE]; + ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); + if(ts3Functions.requestChannelSubscribeAll(serverConnectionHandlerID, returnCode) != ERROR_ok) { + ts3Functions.logMessage("Error subscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID); + } + break; + } + case CMD_UNSUBSCRIBEALL: { /* /test unsubscribeall */ + char returnCode[RETURNCODE_BUFSIZE]; + ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); + if(ts3Functions.requestChannelUnsubscribeAll(serverConnectionHandlerID, returnCode) != ERROR_ok) { + ts3Functions.logMessage("Error subscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID); + } + break; + } case CMD_BOOKMARKSLIST: { /* test bookmarkslist */ struct PluginBookmarkList* list; unsigned int error = ts3Functions.getBookmarkList(&list); @@ -466,9 +430,9 @@ int ts3plugin_processCommand(uint64 serverConnectionHandlerID, const char* comma } break; } - } + } - return 0; /* Plugin handled command */ + return 0; /* Plugin handled command */ } /* Client changed current server connection handler */ @@ -483,7 +447,7 @@ void ts3plugin_currentServerConnectionChanged(uint64 serverConnectionHandlerID) /* Static title shown in the left column in the info frame */ const char* ts3plugin_infoTitle() { - return "WIFILED plugin"; + return "WIFILED plugin"; } /* @@ -528,7 +492,7 @@ void ts3plugin_infoData(uint64 serverConnectionHandlerID, uint64 id, enum Plugin /* Required to release the memory for parameter "data" allocated in ts3plugin_infoData and ts3plugin_initMenus */ void ts3plugin_freeMemory(void* data) { - free(data); + free(data); } /* @@ -537,17 +501,17 @@ void ts3plugin_freeMemory(void* data) { * This function is optional. If missing, no autoload is assumed. */ int ts3plugin_requestAutoload() { - return 1; /* 1 = request autoloaded, 0 = do not request autoload */ + return 1; /* 1 = request autoloaded, 0 = do not request autoload */ } /* Helper function to create a menu item */ static struct PluginMenuItem* createMenuItem(enum PluginMenuType type, int id, const char* text, const char* icon) { - struct PluginMenuItem* menuItem = (struct PluginMenuItem*)malloc(sizeof(struct PluginMenuItem)); - menuItem->type = type; - menuItem->id = id; - _strcpy(menuItem->text, PLUGIN_MENU_BUFSZ, text); - _strcpy(menuItem->icon, PLUGIN_MENU_BUFSZ, icon); - return menuItem; + struct PluginMenuItem* menuItem = (struct PluginMenuItem*)malloc(sizeof(struct PluginMenuItem)); + menuItem->type = type; + menuItem->id = id; + _strcpy(menuItem->text, PLUGIN_MENU_BUFSZ, text); + _strcpy(menuItem->icon, PLUGIN_MENU_BUFSZ, icon); + return menuItem; } /* Some makros to make the code to create menu items a bit more readable */ @@ -561,13 +525,13 @@ static struct PluginMenuItem* createMenuItem(enum PluginMenuType type, int id, c * These IDs are freely choosable by the plugin author. It's not really needed to use an enum, it just looks prettier. */ enum { - MENU_ID_CLIENT_1 = 1, - MENU_ID_CLIENT_2, - MENU_ID_CHANNEL_1, - MENU_ID_CHANNEL_2, - MENU_ID_CHANNEL_3, - MENU_ID_GLOBAL_1, - MENU_ID_GLOBAL_2 + MENU_ID_CLIENT_1 = 1, + MENU_ID_CLIENT_2, + MENU_ID_CHANNEL_1, + MENU_ID_CHANNEL_2, + MENU_ID_CHANNEL_3, + MENU_ID_GLOBAL_1, + MENU_ID_GLOBAL_2 }; /* @@ -577,59 +541,59 @@ enum { * If plugin menus are not used by a plugin, do not implement this function or return NULL. */ void ts3plugin_initMenus(struct PluginMenuItem*** menuItems, char** menuIcon) { - /* - * Create the menus - * There are three types of menu items: - * - PLUGIN_MENU_TYPE_CLIENT: Client context menu - * - PLUGIN_MENU_TYPE_CHANNEL: Channel context menu - * - PLUGIN_MENU_TYPE_GLOBAL: "Plugins" menu in menu bar of main window - * - * Menu IDs are used to identify the menu item when ts3plugin_onMenuItemEvent is called - * - * The menu text is required, max length is 128 characters - * - * The icon is optional, max length is 128 characters. When not using icons, just pass an empty string. - * Icons are loaded from a subdirectory in the TeamSpeak client plugins folder. The subdirectory must be named like the - * plugin filename, without dll/so/dylib suffix - * e.g. for "test_plugin.dll", icon "1.png" is loaded from \plugins\test_plugin\1.png - */ + /* + * Create the menus + * There are three types of menu items: + * - PLUGIN_MENU_TYPE_CLIENT: Client context menu + * - PLUGIN_MENU_TYPE_CHANNEL: Channel context menu + * - PLUGIN_MENU_TYPE_GLOBAL: "Plugins" menu in menu bar of main window + * + * Menu IDs are used to identify the menu item when ts3plugin_onMenuItemEvent is called + * + * The menu text is required, max length is 128 characters + * + * The icon is optional, max length is 128 characters. When not using icons, just pass an empty string. + * Icons are loaded from a subdirectory in the TeamSpeak client plugins folder. The subdirectory must be named like the + * plugin filename, without dll/so/dylib suffix + * e.g. for "test_plugin.dll", icon "1.png" is loaded from \plugins\test_plugin\1.png + */ - BEGIN_CREATE_MENUS(0); /* IMPORTANT: Number of menu items must be correct! */ - //CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CLIENT, MENU_ID_CLIENT_1, "Client item 1", "1.png"); - //CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CLIENT, MENU_ID_CLIENT_2, "Client item 2", "2.png"); - //CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CHANNEL, MENU_ID_CHANNEL_1, "Channel item 1", "1.png"); - //CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CHANNEL, MENU_ID_CHANNEL_2, "Channel item 2", "2.png"); - //CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CHANNEL, MENU_ID_CHANNEL_3, "Channel item 3", "3.png"); - //CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_GLOBAL, MENU_ID_GLOBAL_1, "Global item 1", "1.png"); - //CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_GLOBAL, MENU_ID_GLOBAL_2, "Global item 2", "2.png"); - END_CREATE_MENUS; /* Includes an assert checking if the number of menu items matched */ + BEGIN_CREATE_MENUS(0); /* IMPORTANT: Number of menu items must be correct! */ + //CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CLIENT, MENU_ID_CLIENT_1, "Client item 1", "1.png"); + //CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CLIENT, MENU_ID_CLIENT_2, "Client item 2", "2.png"); + //CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CHANNEL, MENU_ID_CHANNEL_1, "Channel item 1", "1.png"); + //CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CHANNEL, MENU_ID_CHANNEL_2, "Channel item 2", "2.png"); + //CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CHANNEL, MENU_ID_CHANNEL_3, "Channel item 3", "3.png"); + //CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_GLOBAL, MENU_ID_GLOBAL_1, "Global item 1", "1.png"); + //CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_GLOBAL, MENU_ID_GLOBAL_2, "Global item 2", "2.png"); + END_CREATE_MENUS; /* Includes an assert checking if the number of menu items matched */ - /* - * Specify an optional icon for the plugin. This icon is used for the plugins submenu within context and main menus - * If unused, set menuIcon to NULL - */ - *menuIcon = (char*)malloc(PLUGIN_MENU_BUFSZ * sizeof(char)); - _strcpy(*menuIcon, PLUGIN_MENU_BUFSZ, "t.png"); + /* + * Specify an optional icon for the plugin. This icon is used for the plugins submenu within context and main menus + * If unused, set menuIcon to NULL + */ + *menuIcon = (char*)malloc(PLUGIN_MENU_BUFSZ * sizeof(char)); + _strcpy(*menuIcon, PLUGIN_MENU_BUFSZ, "t.png"); - /* - * Menus can be enabled or disabled with: ts3Functions.setPluginMenuEnabled(pluginID, menuID, 0|1); - * Test it with plugin command: /test enablemenu <0|1> - * Menus are enabled by default. Please note that shown menus will not automatically enable or disable when calling this function to - * ensure Qt menus are not modified by any thread other the UI thread. The enabled or disable state will change the next time a - * menu is displayed. - */ - /* For example, this would disable MENU_ID_GLOBAL_2: */ - /* ts3Functions.setPluginMenuEnabled(pluginID, MENU_ID_GLOBAL_2, 0); */ + /* + * Menus can be enabled or disabled with: ts3Functions.setPluginMenuEnabled(pluginID, menuID, 0|1); + * Test it with plugin command: /test enablemenu <0|1> + * Menus are enabled by default. Please note that shown menus will not automatically enable or disable when calling this function to + * ensure Qt menus are not modified by any thread other the UI thread. The enabled or disable state will change the next time a + * menu is displayed. + */ + /* For example, this would disable MENU_ID_GLOBAL_2: */ + /* ts3Functions.setPluginMenuEnabled(pluginID, MENU_ID_GLOBAL_2, 0); */ - /* All memory allocated in this function will be automatically released by the TeamSpeak client later by calling ts3plugin_freeMemory */ + /* All memory allocated in this function will be automatically released by the TeamSpeak client later by calling ts3plugin_freeMemory */ } /* 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; + 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 */ @@ -643,16 +607,16 @@ static struct PluginHotkey* createHotkey(const char* keyword, const char* descri * 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(3); /* Create 3 hotkeys. Size must be correct for allocating memory. */ - CREATE_HOTKEY("keyword_1", "Test hotkey 1"); - CREATE_HOTKEY("keyword_2", "Test hotkey 2"); - CREATE_HOTKEY("keyword_3", "Test hotkey 3"); - END_CREATE_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(3); /* Create 3 hotkeys. Size must be correct for allocating memory. */ + CREATE_HOTKEY("keyword_1", "Test hotkey 1"); + CREATE_HOTKEY("keyword_2", "Test hotkey 2"); + CREATE_HOTKEY("keyword_3", "Test hotkey 3"); + END_CREATE_HOTKEYS; - /* The client will call ts3plugin_freeMemory to release all allocated memory */ + /* The client will call ts3plugin_freeMemory to release all allocated memory */ } /************************** TeamSpeak callbacks ***************************/ @@ -672,7 +636,7 @@ void ts3plugin_onConnectStatusChangeEvent(uint64 serverConnectionHandlerID, int anyID myID; uint64* ids; size_t i; - unsigned int error; + unsigned int error; /* Print clientlib version */ if(ts3Functions.getClientLibVersion(&s) == ERROR_ok) { @@ -683,15 +647,15 @@ void ts3plugin_onConnectStatusChangeEvent(uint64 serverConnectionHandlerID, int return; } - /* Write plugin name and version to log */ + /* Write plugin name and version to log */ snprintf(msg, sizeof(msg), "Plugin %s, Version %s, Author: %s", ts3plugin_name(), ts3plugin_version(), ts3plugin_author()); ts3Functions.logMessage(msg, LogLevel_INFO, "Plugin", serverConnectionHandlerID); /* Print virtual server name */ if((error = ts3Functions.getServerVariableAsString(serverConnectionHandlerID, VIRTUALSERVER_NAME, &s)) != ERROR_ok) { - if(error != ERROR_not_connected) { /* Don't spam error in this case (failed to connect) */ - ts3Functions.logMessage("Error querying server name", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - } + if(error != ERROR_not_connected) { /* Don't spam error in this case (failed to connect) */ + ts3Functions.logMessage("Error querying server name", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); + } return; } printf("PLUGIN: Server name: %s\n", s); @@ -742,16 +706,16 @@ void ts3plugin_onConnectStatusChangeEvent(uint64 serverConnectionHandlerID, int } for(i=0; ids[i]; i++) { if((error = ts3Functions.getServerVariableAsString(ids[i], VIRTUALSERVER_NAME, &s)) != ERROR_ok) { - if(error != ERROR_not_connected) { /* Don't spam error in this case (failed to connect) */ - ts3Functions.logMessage("Error querying server name", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - } + if(error != ERROR_not_connected) { /* Don't spam error in this case (failed to connect) */ + ts3Functions.logMessage("Error querying server name", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); + } continue; } printf("- %llu - %s\n", (long long unsigned int)ids[i], s); ts3Functions.freeMemory(s); } ts3Functions.freeMemory(ids); - myClientID = myID; + myClientID = myID; } } @@ -807,15 +771,15 @@ void ts3plugin_onServerUpdatedEvent(uint64 serverConnectionHandlerID) { } int ts3plugin_onServerErrorEvent(uint64 serverConnectionHandlerID, const char* errorMessage, unsigned int error, const char* returnCode, const char* extraMessage) { - printf("PLUGIN: onServerErrorEvent %llu %s %d %s\n", (long long unsigned int)serverConnectionHandlerID, errorMessage, error, (returnCode ? returnCode : "")); - if(returnCode) { - /* A plugin could now check the returnCode with previously (when calling a function) remembered returnCodes and react accordingly */ - /* In case of using a a plugin return code, the plugin can return: - * 0: Client will continue handling this error (print to chat tab) - * 1: Client will ignore this error, the plugin announces it has handled it */ - return 1; - } - return 0; /* If no plugin return code was used, the return value of this function is ignored */ + printf("PLUGIN: onServerErrorEvent %llu %s %d %s\n", (long long unsigned int)serverConnectionHandlerID, errorMessage, error, (returnCode ? returnCode : "")); + if(returnCode) { + /* A plugin could now check the returnCode with previously (when calling a function) remembered returnCodes and react accordingly */ + /* In case of using a a plugin return code, the plugin can return: + * 0: Client will continue handling this error (print to chat tab) + * 1: Client will ignore this error, the plugin announces it has handled it */ + return 1; + } + 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) { @@ -824,52 +788,40 @@ void ts3plugin_onServerStopEvent(uint64 serverConnectionHandlerID, const char* s int ts3plugin_onTextMessageEvent(uint64 serverConnectionHandlerID, anyID targetMode, anyID toID, anyID fromID, const char* fromName, const char* fromUniqueIdentifier, const char* message, int ffIgnored) { printf("PLUGIN: onTextMessageEvent %llu %d %d %s %s %d\n", (long long unsigned int)serverConnectionHandlerID, targetMode, fromID, fromName, message, ffIgnored); - /* Friend/Foe manager has ignored the message, so ignore here as well. */ - if(ffIgnored) { - return 0; /* Client will ignore the message anyways, so return value here doesn't matter */ - } + /* Friend/Foe manager has ignored the message, so ignore here as well. */ + if(ffIgnored) { + return 0; /* Client will ignore the message anyways, so return value here doesn't matter */ + } #if 0 - { - /* Example code: Autoreply to sender */ - /* Disabled because quite annoying, but should give you some ideas what is possible here */ - /* Careful, when two clients use this, they will get banned quickly... */ - anyID myID; - if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) { - ts3Functions.logMessage("Error querying own client id", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - return 0; - } - if(fromID != myID) { /* Don't reply when source is own client */ - if(ts3Functions.requestSendPrivateTextMsg(serverConnectionHandlerID, "Text message back!", fromID, NULL) != ERROR_ok) { - ts3Functions.logMessage("Error requesting send text message", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - } - } - } + { + /* Example code: Autoreply to sender */ + /* Disabled because quite annoying, but should give you some ideas what is possible here */ + /* Careful, when two clients use this, they will get banned quickly... */ + anyID myID; + if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) { + ts3Functions.logMessage("Error querying own client id", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); + return 0; + } + if(fromID != myID) { /* Don't reply when source is own client */ + if(ts3Functions.requestSendPrivateTextMsg(serverConnectionHandlerID, "Text message back!", fromID, NULL) != ERROR_ok) { + ts3Functions.logMessage("Error requesting send text message", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); + } + } + } #endif return 0; /* 0 = handle normally, 1 = client will ignore the text message */ } void ts3plugin_onTalkStatusChangeEvent(uint64 serverConnectionHandlerID, int status, int isReceivedWhisper, anyID clientID) { - /* Demonstrate usage of getClientDisplayName */ - char name[512]; - if(ts3Functions.getClientDisplayName(serverConnectionHandlerID, clientID, name, 512) == ERROR_ok) { - if (clientID == myClientID) { -// if (curl) { -// if (status == STATUS_TALKING) { -// curl_easy_setopt(curl, CURLOPT_URL, LED_URL_SAVE); -// res = curl_easy_perform(curl); - -// curl_easy_setopt(curl, CURLOPT_URL, LED_URL_ON); -// res = curl_easy_perform(curl); -// } -// else { -// curl_easy_setopt(curl, CURLOPT_URL, LED_URL_OFF); -// res = curl_easy_perform(curl); -// } -// } - } - } + char name[512]; + if (clientID == myClientID) { + if (status == STATUS_TALKING) + mLedHandler->talkingStarted(); + else + mLedHandler->talkingEnded(); + } } void ts3plugin_onConnectionInfoEvent(uint64 serverConnectionHandlerID, anyID clientID) { @@ -933,9 +885,9 @@ int ts3plugin_onClientPokeEvent(uint64 serverConnectionHandlerID, anyID fromClie printf("PLUGIN onClientPokeEvent: %llu %d %s %s %d\n", (long long unsigned int)serverConnectionHandlerID, fromClientID, pokerName, message, ffIgnored); - /* Check if the Friend/Foe manager has already blocked this poke */ - if(ffIgnored) { - return 0; /* Client will block anyways, doesn't matter what we return */ + /* Check if the Friend/Foe manager has already blocked this poke */ + if(ffIgnored) { + return 0; /* Client will block anyways, doesn't matter what we return */ } // if (curl) { @@ -1019,7 +971,7 @@ void ts3plugin_onClientChannelGroupChangedEvent(uint64 serverConnectionHandlerID } 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 */ + return 0; /* See onServerErrorEvent for return code description */ } void ts3plugin_onPermissionListGroupEndIDEvent(uint64 serverConnectionHandlerID, unsigned int groupEndID) { @@ -1083,14 +1035,14 @@ void ts3plugin_onComplainListEvent(uint64 serverConnectionHandlerID, uint64 targ } void ts3plugin_onBanListEvent(uint64 serverConnectionHandlerID, uint64 banid, const char* ip, const char* name, const char* uid, const char* mytsid, uint64 creationTime, uint64 durationTime, const char* invokerName, - uint64 invokercldbid, const char* invokeruid, const char* reason, int numberOfEnforcements, const char* lastNickName) { + 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, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity) { - printf("ON PLUGIN COMMAND: %s %s %d %s %s\n", pluginName, pluginCommand, invokerClientID, invokerName, invokerUniqueIdentity); + printf("ON PLUGIN COMMAND: %s %s %d %s %s\n", pluginName, pluginCommand, invokerClientID, invokerName, invokerUniqueIdentity); } void ts3plugin_onIncomingClientQueryEvent(uint64 serverConnectionHandlerID, const char* commandText) { @@ -1106,13 +1058,13 @@ void ts3plugin_onServerTemporaryPasswordListEvent(uint64 serverConnectionHandler * This callback can be called spontaneously or in response to ts3Functions.getAvatar() */ void ts3plugin_onAvatarUpdated(uint64 serverConnectionHandlerID, anyID clientID, const char* avatarPath) { - /* If avatarPath is NULL, the avatar got deleted */ - /* If not NULL, avatarPath contains the path to the avatar file in the TS3Client cache */ - if(avatarPath != NULL) { - printf("onAvatarUpdated: %llu %d %s\n", (long long unsigned int)serverConnectionHandlerID, clientID, avatarPath); - } else { - printf("onAvatarUpdated: %llu %d - deleted\n", (long long unsigned int)serverConnectionHandlerID, clientID); - } + /* If avatarPath is NULL, the avatar got deleted */ + /* If not NULL, avatarPath contains the path to the avatar file in the TS3Client cache */ + if(avatarPath != NULL) { + printf("onAvatarUpdated: %llu %d %s\n", (long long unsigned int)serverConnectionHandlerID, clientID, avatarPath); + } else { + printf("onAvatarUpdated: %llu %d - deleted\n", (long long unsigned int)serverConnectionHandlerID, clientID); + } } /* @@ -1125,59 +1077,59 @@ void ts3plugin_onAvatarUpdated(uint64 serverConnectionHandlerID, anyID clientID, * - 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) { - printf("PLUGIN: onMenuItemEvent: serverConnectionHandlerID=%llu, type=%d, menuItemID=%d, selectedItemID=%llu\n", (long long unsigned int)serverConnectionHandlerID, type, menuItemID, (long long unsigned int)selectedItemID); - switch(type) { - case PLUGIN_MENU_TYPE_GLOBAL: - /* Global menu item was triggered. selectedItemID is unused and set to zero. */ - switch(menuItemID) { - case MENU_ID_GLOBAL_1: - /* Menu global 1 was triggered */ - break; - case MENU_ID_GLOBAL_2: - /* Menu global 2 was triggered */ - break; - default: - break; - } - break; - case PLUGIN_MENU_TYPE_CHANNEL: - /* Channel contextmenu item was triggered. selectedItemID is the channelID of the selected channel */ - switch(menuItemID) { - case MENU_ID_CHANNEL_1: - /* Menu channel 1 was triggered */ - break; - case MENU_ID_CHANNEL_2: - /* Menu channel 2 was triggered */ - break; - case MENU_ID_CHANNEL_3: - /* Menu channel 3 was triggered */ - break; - default: - break; - } - break; - case PLUGIN_MENU_TYPE_CLIENT: - /* Client contextmenu item was triggered. selectedItemID is the clientID of the selected client */ - switch(menuItemID) { - case MENU_ID_CLIENT_1: - /* Menu client 1 was triggered */ - break; - case MENU_ID_CLIENT_2: - /* Menu client 2 was triggered */ - break; - default: - break; - } - break; - default: - break; - } + printf("PLUGIN: onMenuItemEvent: serverConnectionHandlerID=%llu, type=%d, menuItemID=%d, selectedItemID=%llu\n", (long long unsigned int)serverConnectionHandlerID, type, menuItemID, (long long unsigned int)selectedItemID); + switch(type) { + case PLUGIN_MENU_TYPE_GLOBAL: + /* Global menu item was triggered. selectedItemID is unused and set to zero. */ + switch(menuItemID) { + case MENU_ID_GLOBAL_1: + /* Menu global 1 was triggered */ + break; + case MENU_ID_GLOBAL_2: + /* Menu global 2 was triggered */ + break; + default: + break; + } + break; + case PLUGIN_MENU_TYPE_CHANNEL: + /* Channel contextmenu item was triggered. selectedItemID is the channelID of the selected channel */ + switch(menuItemID) { + case MENU_ID_CHANNEL_1: + /* Menu channel 1 was triggered */ + break; + case MENU_ID_CHANNEL_2: + /* Menu channel 2 was triggered */ + break; + case MENU_ID_CHANNEL_3: + /* Menu channel 3 was triggered */ + break; + default: + break; + } + break; + case PLUGIN_MENU_TYPE_CLIENT: + /* Client contextmenu item was triggered. selectedItemID is the clientID of the selected client */ + switch(menuItemID) { + case MENU_ID_CLIENT_1: + /* Menu client 1 was triggered */ + break; + case MENU_ID_CLIENT_2: + /* Menu client 2 was triggered */ + break; + default: + break; + } + break; + default: + break; + } } /* 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); - /* Identify the hotkey by keyword ("keyword_1", "keyword_2" or "keyword_3" in this example) and handle here... */ + printf("PLUGIN: Hotkey event: %s\n", keyword); + /* Identify the hotkey by keyword ("keyword_1", "keyword_2" or "keyword_3" in this example) and handle here... */ } /* Called when recording a hotkey has finished after calling ts3Functions.requestHotkeyInputDialog */ @@ -1187,20 +1139,21 @@ void ts3plugin_onHotkeyRecordedEvent(const char* keyword, const char* key) { // This function receives your key Identifier you send to notifyKeyEvent and should return // the friendly device name of the device this hotkey originates from. Used for display in UI. const char* ts3plugin_keyDeviceName(const char* keyIdentifier) { - return NULL; + return NULL; } // This function translates the given key identifier to a friendly key name for display in the UI const char* ts3plugin_displayKeyText(const char* keyIdentifier) { - return NULL; + return NULL; } // This is used internally as a prefix for hotkeys so we can store them without collisions. // Should be unique across plugins. const char* ts3plugin_keyPrefix() { - return NULL; + return NULL; } /* Called when client custom nickname changed */ void ts3plugin_onClientDisplayNameChanged(uint64 serverConnectionHandlerID, anyID clientID, const char* displayName, const char* uniqueClientIdentifier) { } + diff --git a/src/plugin.h b/src/plugin.h index f045cb4..ded8748 100644 --- a/src/plugin.h +++ b/src/plugin.h @@ -7,16 +7,30 @@ #ifndef PLUGIN_H #define PLUGIN_H +#include + #if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) +#include #define PLUGINS_EXPORTDLL __declspec(dllexport) #else #define PLUGINS_EXPORTDLL __attribute__ ((visibility("default"))) #endif +#include "ledhandler.h" +#include "ts3_functions.h" + +#include +#include +#include +#include + #ifdef __cplusplus extern "C" { #endif +QUdpSocket *mUdpSock; +LEDHandler *mLedHandler; + /* Required functions */ PLUGINS_EXPORTDLL const char* ts3plugin_name(); PLUGINS_EXPORTDLL const char* ts3plugin_version();