SHARE
TWEET

Untitled

a guest Jan 26th, 2019 12 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  * TeamSpeak 3 demo plugin
  3.  *
  4.  * Copyright (c) 2008-2017 TeamSpeak Systems GmbH
  5.  */
  6.  
  7. #ifdef _WIN32
  8. #pragma warning (disable : 4100)  /* Disable Unreferenced parameter warning */
  9. #include <Windows.h>
  10. #endif
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <assert.h>
  16. #include "teamspeak/public_errors.h"
  17. #include "teamspeak/public_errors_rare.h"
  18. #include "teamspeak/public_definitions.h"
  19. #include "teamspeak/public_rare_definitions.h"
  20. #include "teamspeak/clientlib_publicdefinitions.h"
  21. #include "ts3_functions.h"
  22. #include "plugin.h"
  23.  
  24. static struct TS3Functions ts3Functions;
  25.  
  26. #ifdef _WIN32
  27. #define _strcpy(dest, destSize, src) strcpy_s(dest, destSize, src)
  28. #define snprintf sprintf_s
  29. #else
  30. #define _strcpy(dest, destSize, src) { strncpy(dest, src, destSize-1); (dest)[destSize-1] = '\0'; }
  31. #endif
  32.  
  33. #define PLUGIN_API_VERSION 22
  34.  
  35. #define PATH_BUFSIZE 512
  36. #define COMMAND_BUFSIZE 128
  37. #define INFODATA_BUFSIZE 128
  38. #define SERVERINFO_BUFSIZE 256
  39. #define CHANNELINFO_BUFSIZE 512
  40. #define RETURNCODE_BUFSIZE 128
  41.  
  42. static char* pluginID = 1;
  43.  
  44. #ifdef _WIN32
  45. /* Helper function to convert wchar_T to Utf-8 encoded strings on Windows */
  46. static int wcharToUtf8(const wchar_t* str, char** result) {
  47.     int outlen = WideCharToMultiByte(CP_UTF8, 0, str, -1, 0, 0, 0, 0);
  48.     *result = (char*)malloc(outlen);
  49.     if(WideCharToMultiByte(CP_UTF8, 0, str, -1, *result, outlen, 0, 0) == 0) {
  50.         *result = NULL;
  51.         return -1;
  52.     }
  53.     return 0;
  54. }
  55. #endif
  56.  
  57. /*********************************** Required functions ************************************/
  58. /*
  59.  * If any of these required functions is not implemented, TS3 will refuse to load the plugin
  60.  */
  61.  
  62. /* Unique name identifying this plugin */
  63. const char* ts3plugin_name() {
  64. #ifdef _WIN32
  65.     /* TeamSpeak expects UTF-8 encoded characters. Following demonstrates a possibility how to convert UTF-16 wchar_t into UTF-8. */
  66.     static char* result = NULL;  /* Static variable so it's allocated only once */
  67.     if(!result) {
  68.         const wchar_t* name = L"Test Plugin";
  69.         if(wcharToUtf8(name, &result) == -1) {  /* Convert name into UTF-8 encoded result */
  70.             result = "Test Plugin";  /* Conversion failed, fallback here */
  71.         }
  72.     }
  73.     return result;
  74. #else
  75.     return "Test Plugin";
  76. #endif
  77. }
  78.  
  79. /* Plugin version */
  80. const char* ts3plugin_version() {
  81.     return "1.2";
  82. }
  83.  
  84. /* Plugin API version. Must be the same as the clients API major version, else the plugin fails to load. */
  85. int ts3plugin_apiVersion() {
  86.     return PLUGIN_API_VERSION;
  87. }
  88.  
  89. /* Plugin author */
  90. const char* ts3plugin_author() {
  91.     /* If you want to use wchar_t, see ts3plugin_name() on how to use */
  92.     return "TeamSpeak Systems GmbH";
  93. }
  94.  
  95. /* Plugin description */
  96. const char* ts3plugin_description() {
  97.     /* If you want to use wchar_t, see ts3plugin_name() on how to use */
  98.     return "This plugin demonstrates the TeamSpeak 3 client plugin architecture.";
  99. }
  100.  
  101. /* Set TeamSpeak 3 callback functions */
  102. void ts3plugin_setFunctionPointers(const struct TS3Functions funcs) {
  103.     ts3Functions = funcs;
  104. }
  105.  
  106. /*
  107.  * Custom code called right after loading the plugin. Returns 0 on success, 1 on failure.
  108.  * If the function returns 1 on failure, the plugin will be unloaded again.
  109.  */
  110. int ts3plugin_init() {
  111.     char appPath[PATH_BUFSIZE];
  112.     char resourcesPath[PATH_BUFSIZE];
  113.     char configPath[PATH_BUFSIZE];
  114.     char pluginPath[PATH_BUFSIZE];
  115.  
  116.     /* Your plugin init code here */
  117.     printf("PLUGIN: init\n");
  118.  
  119.     /* Example on how to query application, resources and configuration paths from client */
  120.     /* Note: Console client returns empty string for app and resources path */
  121.     ts3Functions.getAppPath(appPath, PATH_BUFSIZE);
  122.     ts3Functions.getResourcesPath(resourcesPath, PATH_BUFSIZE);
  123.     ts3Functions.getConfigPath(configPath, PATH_BUFSIZE);
  124.     ts3Functions.getPluginPath(pluginPath, PATH_BUFSIZE, pluginID);
  125.  
  126.     printf("PLUGIN: App path: %s\nResources path: %s\nConfig path: %s\nPlugin path: %s\n", appPath, resourcesPath, configPath, pluginPath);
  127.  
  128.     return 0;  /* 0 = success, 1 = failure, -2 = failure but client will not show a "failed to load" warning */
  129.     /* -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
  130.      * the plugin again, avoiding the show another dialog by the client telling the user the plugin failed to load.
  131.      * For normal case, if a plugin really failed to load because of an error, the correct return value is 1. */
  132. }
  133.  
  134. /* Custom code called right before the plugin is unloaded */
  135. void ts3plugin_shutdown() {
  136.     /* Your plugin cleanup code here */
  137.     printf("PLUGIN: shutdown\n");
  138.  
  139.     /*
  140.      * Note:
  141.      * If your plugin implements a settings dialog, it must be closed and deleted here, else the
  142.      * TeamSpeak client will most likely crash (DLL removed but dialog from DLL code still open).
  143.      */
  144.  
  145.     /* Free pluginID if we registered it */
  146.     if(pluginID) {
  147.         free(pluginID);
  148.         pluginID = NULL;
  149.     }
  150. }
  151.  
  152. /****************************** Optional functions ********************************/
  153. /*
  154.  * Following functions are optional, if not needed you don't need to implement them.
  155.  */
  156.  
  157. /* 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). */
  158. int ts3plugin_offersConfigure() {
  159.     printf("PLUGIN: offersConfigure\n");
  160.     /*
  161.      * Return values:
  162.      * PLUGIN_OFFERS_NO_CONFIGURE         - Plugin does not implement ts3plugin_configure
  163.      * PLUGIN_OFFERS_CONFIGURE_NEW_THREAD - Plugin does implement ts3plugin_configure and requests to run this function in an own thread
  164.      * PLUGIN_OFFERS_CONFIGURE_QT_THREAD  - Plugin does implement ts3plugin_configure and requests to run this function in the Qt GUI thread
  165.      */
  166.     return PLUGIN_OFFERS_NO_CONFIGURE;  /* In this case ts3plugin_configure does not need to be implemented */
  167. }
  168.  
  169. /* Plugin might offer a configuration window. If ts3plugin_offersConfigure returns 0, this function does not need to be implemented. */
  170. void ts3plugin_configure(void* handle, void* qParentWidget) {
  171.     printf("PLUGIN: configure\n");
  172. }
  173.  
  174. /*
  175.  * 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
  176.  * automatically called after the plugin was initialized. This function is optional. If you don't use these features, this function can be omitted.
  177.  * Note the passed pluginID parameter is no longer valid after calling this function, so you must copy it and store it in the plugin.
  178.  */
  179. void ts3plugin_registerPluginID(const char* id) {
  180.     const size_t sz = strlen(id) + 1;
  181.     pluginID = (char*)malloc(sz * sizeof(char));
  182.     _strcpy(pluginID, sz, id);  /* The id buffer will invalidate after exiting this function */
  183.     printf("PLUGIN: registerPluginID: %s\n", pluginID);
  184. }
  185.  
  186. /* Plugin command keyword. Return NULL or "" if not used. */
  187. const char* ts3plugin_commandKeyword() {
  188.     return "test";
  189. }
  190.  
  191. static void print_and_free_bookmarks_list(struct PluginBookmarkList* list)
  192. {
  193.     int i;
  194.     for (i = 0; i < list->itemcount; ++i) {
  195.         if (list->items[i].isFolder) {
  196.             printf("Folder: name=%s\n", list->items[i].name);
  197.             print_and_free_bookmarks_list(list->items[i].folder);
  198.             ts3Functions.freeMemory(list->items[i].name);
  199.         } else {
  200.             printf("Bookmark: name=%s uuid=%s\n", list->items[i].name, list->items[i].uuid);
  201.             ts3Functions.freeMemory(list->items[i].name);
  202.             ts3Functions.freeMemory(list->items[i].uuid);
  203.         }
  204.     }
  205.     ts3Functions.freeMemory(list);
  206. }
  207.  
  208. /* Plugin processes console command. Return 0 if plugin handled the command, 1 if not handled. */
  209. int ts3plugin_processCommand(uint64 serverConnectionHandlerID, const char* command) {
  210.     char buf[COMMAND_BUFSIZE];
  211.     char *s, *param1 = NULL, *param2 = NULL;
  212.     int i = 0;
  213.     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;
  214. #ifdef _WIN32
  215.     char* context = NULL;
  216. #endif
  217.  
  218.     printf("PLUGIN: process command: '%s'\n", command);
  219.  
  220.     _strcpy(buf, COMMAND_BUFSIZE, command);
  221. #ifdef _WIN32
  222.     s = strtok_s(buf, " ", &context);
  223. #else
  224.     s = strtok(buf, " ");
  225. #endif
  226.     while(s != NULL) {
  227.         if(i == 0) {
  228.             if(!strcmp(s, "join")) {
  229.                 cmd = CMD_JOIN;
  230.             } else if(!strcmp(s, "command")) {
  231.                 cmd = CMD_COMMAND;
  232.             } else if(!strcmp(s, "serverinfo")) {
  233.                 cmd = CMD_SERVERINFO;
  234.             } else if(!strcmp(s, "channelinfo")) {
  235.                 cmd = CMD_CHANNELINFO;
  236.             } else if(!strcmp(s, "avatar")) {
  237.                 cmd = CMD_AVATAR;
  238.             } else if(!strcmp(s, "enablemenu")) {
  239.                 cmd = CMD_ENABLEMENU;
  240.             } else if(!strcmp(s, "subscribe")) {
  241.                 cmd = CMD_SUBSCRIBE;
  242.             } else if(!strcmp(s, "unsubscribe")) {
  243.                 cmd = CMD_UNSUBSCRIBE;
  244.             } else if(!strcmp(s, "subscribeall")) {
  245.                 cmd = CMD_SUBSCRIBEALL;
  246.             } else if(!strcmp(s, "unsubscribeall")) {
  247.                 cmd = CMD_UNSUBSCRIBEALL;
  248.             } else if (!strcmp(s, "bookmarkslist")) {
  249.                 cmd = CMD_BOOKMARKSLIST;
  250.             }
  251.         } else if(i == 1) {
  252.             param1 = s;
  253.         } else {
  254.             param2 = s;
  255.         }
  256. #ifdef _WIN32
  257.         s = strtok_s(NULL, " ", &context);
  258. #else
  259.         s = strtok(NULL, " ");
  260. #endif
  261.         i++;
  262.     }
  263.  
  264.     switch(cmd) {
  265.         case CMD_NONE:
  266.             return 1;  /* Command not handled by plugin */
  267.         case CMD_JOIN:  /* /test join <channelID> [optionalCannelPassword] */
  268.             if(param1) {
  269.                 uint64 channelID = (uint64)atoi(param1);
  270.                 char* password = param2 ? param2 : "";
  271.                 char returnCode[RETURNCODE_BUFSIZE];
  272.                 anyID myID;
  273.  
  274.                 /* Get own clientID */
  275.                 if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) {
  276.                     ts3Functions.logMessage("Error querying client ID", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  277.                     break;
  278.                 }
  279.  
  280.                 /* Create return code for requestClientMove function call. If creation fails, returnCode will be NULL, which can be
  281.                  * passed into the client functions meaning no return code is used.
  282.                  * Note: To use return codes, the plugin needs to register a plugin ID using ts3plugin_registerPluginID */
  283.                 ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE);
  284.  
  285.                 /* In a real world plugin, the returnCode should be remembered (e.g. in a dynamic STL vector, if it's a C++ plugin).
  286.                  * onServerErrorEvent can then check the received returnCode, compare with the remembered ones and thus identify
  287.                  * which function call has triggered the event and react accordingly. */
  288.  
  289.                 /* Request joining specified channel using above created return code */
  290.                 if(ts3Functions.requestClientMove(serverConnectionHandlerID, myID, channelID, password, returnCode) != ERROR_ok) {
  291.                     ts3Functions.logMessage("Error requesting client move", LogLevel_INFO, "Plugin", serverConnectionHandlerID);
  292.                 }
  293.             } else {
  294.                 ts3Functions.printMessageToCurrentTab("Missing channel ID parameter.");
  295.             }
  296.             break;
  297.         case CMD_COMMAND:  /* /test command <command> */
  298.             if(param1) {
  299.                 /* Send plugin command to all clients in current channel. In this case targetIds is unused and can be NULL. */
  300.                 if(pluginID) {
  301.                     /* See ts3plugin_registerPluginID for how to obtain a pluginID */
  302.                     printf("PLUGIN: Sending plugin command to current channel: %s\n", param1);
  303.                     ts3Functions.sendPluginCommand(serverConnectionHandlerID, pluginID, param1, PluginCommandTarget_CURRENT_CHANNEL, NULL, NULL);
  304.                 } else {
  305.                     printf("PLUGIN: Failed to send plugin command, was not registered.\n");
  306.                 }
  307.             } else {
  308.                 ts3Functions.printMessageToCurrentTab("Missing command parameter.");
  309.             }
  310.             break;
  311.         case CMD_SERVERINFO: {  /* /test serverinfo */
  312.             /* Query host, port and server password of current server tab.
  313.              * The password parameter can be NULL if the plugin does not want to receive the server password.
  314.              * Note: Server password is only available if the user has actually used it when connecting. If a user has
  315.              * connected with the permission to ignore passwords (b_virtualserver_join_ignore_password) and the password,
  316.              * was not entered, it will not be available.
  317.              * getServerConnectInfo returns 0 on success, 1 on error or if current server tab is disconnected. */
  318.             char host[SERVERINFO_BUFSIZE];
  319.             /*char password[SERVERINFO_BUFSIZE];*/
  320.             char* password = NULL;  /* Don't receive server password */
  321.             unsigned short port;
  322.             if(!ts3Functions.getServerConnectInfo(serverConnectionHandlerID, host, &port, password, SERVERINFO_BUFSIZE)) {
  323.                 char msg[SERVERINFO_BUFSIZE];
  324.                 snprintf(msg, sizeof(msg), "Server Connect Info: %s:%d", host, port);
  325.                 ts3Functions.printMessageToCurrentTab(msg);
  326.             } else {
  327.                 ts3Functions.printMessageToCurrentTab("No server connect info available.");
  328.             }
  329.             break;
  330.         }
  331.         case CMD_CHANNELINFO: {  /* /test channelinfo */
  332.             /* Query channel path and password of current server tab.
  333.              * The password parameter can be NULL if the plugin does not want to receive the channel password.
  334.              * Note: Channel password is only available if the user has actually used it when entering the channel. If a user has
  335.              * entered a channel with the permission to ignore passwords (b_channel_join_ignore_password) and the password,
  336.              * was not entered, it will not be available.
  337.              * getChannelConnectInfo returns 0 on success, 1 on error or if current server tab is disconnected. */
  338.             char path[CHANNELINFO_BUFSIZE];
  339.             /*char password[CHANNELINFO_BUFSIZE];*/
  340.             char* password = NULL;  /* Don't receive channel password */
  341.  
  342.             /* Get own clientID and channelID */
  343.             anyID myID;
  344.             uint64 myChannelID;
  345.             if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) {
  346.                 ts3Functions.logMessage("Error querying client ID", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  347.                 break;
  348.             }
  349.             /* Get own channel ID */
  350.             if(ts3Functions.getChannelOfClient(serverConnectionHandlerID, myID, &myChannelID) != ERROR_ok) {
  351.                 ts3Functions.logMessage("Error querying channel ID", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  352.                 break;
  353.             }
  354.  
  355.             /* Get channel connect info of own channel */
  356.             if(!ts3Functions.getChannelConnectInfo(serverConnectionHandlerID, myChannelID, path, password, CHANNELINFO_BUFSIZE)) {
  357.                 char msg[CHANNELINFO_BUFSIZE];
  358.                 snprintf(msg, sizeof(msg), "Channel Connect Info: %s", path);
  359.                 ts3Functions.printMessageToCurrentTab(msg);
  360.             } else {
  361.                 ts3Functions.printMessageToCurrentTab("No channel connect info available.");
  362.             }
  363.             break;
  364.         }
  365.         case CMD_AVATAR: {  /* /test avatar <clientID> */
  366.             char avatarPath[PATH_BUFSIZE];
  367.             anyID clientID = (anyID)atoi(param1);
  368.             unsigned int error;
  369.  
  370.             memset(avatarPath, 0, PATH_BUFSIZE);
  371.             error = ts3Functions.getAvatar(serverConnectionHandlerID, clientID, avatarPath, PATH_BUFSIZE);
  372.             if(error == ERROR_ok) {  /* ERROR_ok means the client has an avatar set. */
  373.                 if(strlen(avatarPath)) {  /* Avatar path contains the full path to the avatar image in the TS3Client cache directory */
  374.                     printf("Avatar path: %s\n", avatarPath);
  375.                 } else { /* Empty avatar path means the client has an avatar but the image has not yet been cached. The TeamSpeak
  376.                           * client will automatically start the download and call onAvatarUpdated when done */
  377.                     printf("Avatar not yet downloaded, waiting for onAvatarUpdated...\n");
  378.                 }
  379.             } else if(error == ERROR_database_empty_result) {  /* Not an error, the client simply has no avatar set */
  380.                 printf("Client has no avatar\n");
  381.             } else { /* Other error occured (invalid server connection handler ID, invalid client ID, file io error etc) */
  382.                 printf("Error getting avatar: %d\n", error);
  383.             }
  384.             break;
  385.         }
  386.         case CMD_ENABLEMENU:  /* /test enablemenu <menuID> <0|1> */
  387.             if(param1) {
  388.                 int menuID = atoi(param1);
  389.                 int enable = param2 ? atoi(param2) : 0;
  390.                 ts3Functions.setPluginMenuEnabled(pluginID, menuID, enable);
  391.             } else {
  392.                 ts3Functions.printMessageToCurrentTab("Usage is: /test enablemenu <menuID> <0|1>");
  393.             }
  394.             break;
  395.         case CMD_SUBSCRIBE:  /* /test subscribe <channelID> */
  396.             if(param1) {
  397.                 char returnCode[RETURNCODE_BUFSIZE];
  398.                 uint64 channelIDArray[2];
  399.                 channelIDArray[0] = (uint64)atoi(param1);
  400.                 channelIDArray[1] = 0;
  401.                 ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE);
  402.                 if(ts3Functions.requestChannelSubscribe(serverConnectionHandlerID, channelIDArray, returnCode) != ERROR_ok) {
  403.                     ts3Functions.logMessage("Error subscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID);
  404.                 }
  405.             }
  406.             break;
  407.         case CMD_UNSUBSCRIBE:  /* /test unsubscribe <channelID> */
  408.             if(param1) {
  409.                 char returnCode[RETURNCODE_BUFSIZE];
  410.                 uint64 channelIDArray[2];
  411.                 channelIDArray[0] = (uint64)atoi(param1);
  412.                 channelIDArray[1] = 0;
  413.                 ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE);
  414.                 if(ts3Functions.requestChannelUnsubscribe(serverConnectionHandlerID, channelIDArray, NULL) != ERROR_ok) {
  415.                     ts3Functions.logMessage("Error unsubscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID);
  416.                 }
  417.             }
  418.             break;
  419.         case CMD_SUBSCRIBEALL: {  /* /test subscribeall */
  420.             char returnCode[RETURNCODE_BUFSIZE];
  421.             ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE);
  422.             if(ts3Functions.requestChannelSubscribeAll(serverConnectionHandlerID, returnCode) != ERROR_ok) {
  423.                 ts3Functions.logMessage("Error subscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID);
  424.             }
  425.             break;
  426.         }
  427.         case CMD_UNSUBSCRIBEALL: {  /* /test unsubscribeall */
  428.             char returnCode[RETURNCODE_BUFSIZE];
  429.             ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE);
  430.             if(ts3Functions.requestChannelUnsubscribeAll(serverConnectionHandlerID, returnCode) != ERROR_ok) {
  431.                 ts3Functions.logMessage("Error subscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID);
  432.             }
  433.             break;
  434.         }
  435.         case CMD_BOOKMARKSLIST: {  /* test bookmarkslist */
  436.             struct PluginBookmarkList* list;
  437.             unsigned int error = ts3Functions.getBookmarkList(&list);
  438.             if (error == ERROR_ok) {
  439.                 print_and_free_bookmarks_list(list);
  440.             }
  441.             else {
  442.                 ts3Functions.logMessage("Error getting bookmarks list", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  443.             }
  444.             break;
  445.         }
  446.     }
  447.  
  448.     return 0;  /* Plugin handled command */
  449. }
  450.  
  451. /* Client changed current server connection handler */
  452. void ts3plugin_currentServerConnectionChanged(uint64 serverConnectionHandlerID) {
  453.     printf("PLUGIN: currentServerConnectionChanged %llu (%llu)\n", (long long unsigned int)serverConnectionHandlerID, (long long unsigned int)ts3Functions.getCurrentServerConnectionHandlerID());
  454. }
  455.  
  456. /*
  457.  * Implement the following three functions when the plugin should display a line in the server/channel/client info.
  458.  * If any of ts3plugin_infoTitle, ts3plugin_infoData or ts3plugin_freeMemory is missing, the info text will not be displayed.
  459.  */
  460.  
  461. /* Static title shown in the left column in the info frame */
  462. const char* ts3plugin_infoTitle() {
  463.     return "Test plugin info";
  464. }
  465.  
  466. /*
  467.  * Dynamic content shown in the right column in the info frame. Memory for the data string needs to be allocated in this
  468.  * function. The client will call ts3plugin_freeMemory once done with the string to release the allocated memory again.
  469.  * Check the parameter "type" if you want to implement this feature only for specific item types. Set the parameter
  470.  * "data" to NULL to have the client ignore the info data.
  471.  */
  472. void ts3plugin_infoData(uint64 serverConnectionHandlerID, uint64 id, enum PluginItemType type, char** data) {
  473.     char* name;
  474.  
  475.     /* For demonstration purpose, display the name of the currently selected server, channel or client. */
  476.     switch(type) {
  477.         case PLUGIN_SERVER:
  478.             if(ts3Functions.getServerVariableAsString(serverConnectionHandlerID, VIRTUALSERVER_NAME, &name) != ERROR_ok) {
  479.                 printf("Error getting virtual server name\n");
  480.                 return;
  481.             }
  482.             break;
  483.         case PLUGIN_CHANNEL:
  484.             if(ts3Functions.getChannelVariableAsString(serverConnectionHandlerID, id, CHANNEL_NAME, &name) != ERROR_ok) {
  485.                 printf("Error getting channel name\n");
  486.                 return;
  487.             }
  488.             break;
  489.         case PLUGIN_CLIENT:
  490.             if(ts3Functions.getClientVariableAsString(serverConnectionHandlerID, (anyID)id, CLIENT_NICKNAME, &name) != ERROR_ok) {
  491.                 printf("Error getting client nickname\n");
  492.                 return;
  493.             }
  494.             break;
  495.         default:
  496.             printf("Invalid item type: %d\n", type);
  497.             data = NULL;  /* Ignore */
  498.             return;
  499.     }
  500.  
  501.     *data = (char*)malloc(INFODATA_BUFSIZE * sizeof(char));  /* Must be allocated in the plugin! */
  502.     snprintf(*data, INFODATA_BUFSIZE, "The nickname is [I]\"%s\"[/I]", name);  /* bbCode is supported. HTML is not supported */
  503.     ts3Functions.freeMemory(name);
  504. }
  505.  
  506. /* Required to release the memory for parameter "data" allocated in ts3plugin_infoData and ts3plugin_initMenus */
  507. void ts3plugin_freeMemory(void* data) {
  508.     free(data);
  509. }
  510.  
  511. /*
  512.  * Plugin requests to be always automatically loaded by the TeamSpeak 3 client unless
  513.  * the user manually disabled it in the plugin dialog.
  514.  * This function is optional. If missing, no autoload is assumed.
  515.  */
  516. int ts3plugin_requestAutoload() {
  517.     return 0;  /* 1 = request autoloaded, 0 = do not request autoload */
  518. }
  519.  
  520. /* Helper function to create a menu item */
  521. static struct PluginMenuItem* createMenuItem(enum PluginMenuType type, int id, const char* text, const char* icon) {
  522.     struct PluginMenuItem* menuItem = (struct PluginMenuItem*)malloc(sizeof(struct PluginMenuItem));
  523.     menuItem->type = type;
  524.     menuItem->id = id;
  525.     _strcpy(menuItem->text, PLUGIN_MENU_BUFSZ, text);
  526.     _strcpy(menuItem->icon, PLUGIN_MENU_BUFSZ, icon);
  527.     return menuItem;
  528. }
  529.  
  530. /* Some makros to make the code to create menu items a bit more readable */
  531. #define BEGIN_CREATE_MENUS(x) const size_t sz = x + 1; size_t n = 0; *menuItems = (struct PluginMenuItem**)malloc(sizeof(struct PluginMenuItem*) * sz);
  532. #define CREATE_MENU_ITEM(a, b, c, d) (*menuItems)[n++] = createMenuItem(a, b, c, d);
  533. #define END_CREATE_MENUS (*menuItems)[n++] = NULL; assert(n == sz);
  534.  
  535. /*
  536.  * Menu IDs for this plugin. Pass these IDs when creating a menuitem to the TS3 client. When the menu item is triggered,
  537.  * ts3plugin_onMenuItemEvent will be called passing the menu ID of the triggered menu item.
  538.  * These IDs are freely choosable by the plugin author. It's not really needed to use an enum, it just looks prettier.
  539.  */
  540. enum {
  541.     MENU_ID_CLIENT_1 = 1,
  542.     MENU_ID_CLIENT_2,
  543.     MENU_ID_CHANNEL_1,
  544.     MENU_ID_CHANNEL_2,
  545.     MENU_ID_CHANNEL_3,
  546.     MENU_ID_GLOBAL_1,
  547.     MENU_ID_GLOBAL_2
  548. };
  549.  
  550. /*
  551.  * Initialize plugin menus.
  552.  * This function is called after ts3plugin_init and ts3plugin_registerPluginID. A pluginID is required for plugin menus to work.
  553.  * Both ts3plugin_registerPluginID and ts3plugin_freeMemory must be implemented to use menus.
  554.  * If plugin menus are not used by a plugin, do not implement this function or return NULL.
  555.  */
  556. void ts3plugin_initMenus(struct PluginMenuItem*** menuItems, char** menuIcon) {
  557.     /*
  558.      * Create the menus
  559.      * There are three types of menu items:
  560.      * - PLUGIN_MENU_TYPE_CLIENT:  Client context menu
  561.      * - PLUGIN_MENU_TYPE_CHANNEL: Channel context menu
  562.      * - PLUGIN_MENU_TYPE_GLOBAL:  "Plugins" menu in menu bar of main window
  563.      *
  564.      * Menu IDs are used to identify the menu item when ts3plugin_onMenuItemEvent is called
  565.      *
  566.      * The menu text is required, max length is 128 characters
  567.      *
  568.      * The icon is optional, max length is 128 characters. When not using icons, just pass an empty string.
  569.      * Icons are loaded from a subdirectory in the TeamSpeak client plugins folder. The subdirectory must be named like the
  570.      * plugin filename, without dll/so/dylib suffix
  571.      * e.g. for "test_plugin.dll", icon "1.png" is loaded from <TeamSpeak 3 Client install dir>\plugins\test_plugin\1.png
  572.      */
  573.  
  574.     BEGIN_CREATE_MENUS(7);  /* IMPORTANT: Number of menu items must be correct! */
  575.     CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CLIENT,  MENU_ID_CLIENT_1,  "Client item 1",  "1.png");
  576.     CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CLIENT,  MENU_ID_CLIENT_2,  "Client item 2",  "2.png");
  577.     CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CHANNEL, MENU_ID_CHANNEL_1, "Channel item 1", "1.png");
  578.     CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CHANNEL, MENU_ID_CHANNEL_2, "Channel item 2", "2.png");
  579.     CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CHANNEL, MENU_ID_CHANNEL_3, "Channel item 3", "3.png");
  580.     CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_GLOBAL,  MENU_ID_GLOBAL_1,  "Global item 1",  "1.png");
  581.     CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_GLOBAL,  MENU_ID_GLOBAL_2,  "Global item 2",  "2.png");
  582.     END_CREATE_MENUS;  /* Includes an assert checking if the number of menu items matched */
  583.  
  584.     /*
  585.      * Specify an optional icon for the plugin. This icon is used for the plugins submenu within context and main menus
  586.      * If unused, set menuIcon to NULL
  587.      */
  588.     *menuIcon = (char*)malloc(PLUGIN_MENU_BUFSZ * sizeof(char));
  589.     _strcpy(*menuIcon, PLUGIN_MENU_BUFSZ, "t.png");
  590.  
  591.     /*
  592.      * Menus can be enabled or disabled with: ts3Functions.setPluginMenuEnabled(pluginID, menuID, 0|1);
  593.      * Test it with plugin command: /test enablemenu <menuID> <0|1>
  594.      * Menus are enabled by default. Please note that shown menus will not automatically enable or disable when calling this function to
  595.      * ensure Qt menus are not modified by any thread other the UI thread. The enabled or disable state will change the next time a
  596.      * menu is displayed.
  597.      */
  598.     /* For example, this would disable MENU_ID_GLOBAL_2: */
  599.     /* ts3Functions.setPluginMenuEnabled(pluginID, MENU_ID_GLOBAL_2, 0); */
  600.  
  601.     /* All memory allocated in this function will be automatically released by the TeamSpeak client later by calling ts3plugin_freeMemory */
  602. }
  603.  
  604. /* Helper function to create a hotkey */
  605. static struct PluginHotkey* createHotkey(const char* keyword, const char* description) {
  606.     struct PluginHotkey* hotkey = (struct PluginHotkey*)malloc(sizeof(struct PluginHotkey));
  607.     _strcpy(hotkey->keyword, PLUGIN_HOTKEY_BUFSZ, keyword);
  608.     _strcpy(hotkey->description, PLUGIN_HOTKEY_BUFSZ, description);
  609.     return hotkey;
  610. }
  611.  
  612. /* Some makros to make the code to create hotkeys a bit more readable */
  613. #define BEGIN_CREATE_HOTKEYS(x) const size_t sz = x + 1; size_t n = 0; *hotkeys = (struct PluginHotkey**)malloc(sizeof(struct PluginHotkey*) * sz);
  614. #define CREATE_HOTKEY(a, b) (*hotkeys)[n++] = createHotkey(a, b);
  615. #define END_CREATE_HOTKEYS (*hotkeys)[n++] = NULL; assert(n == sz);
  616.  
  617. /*
  618.  * Initialize plugin hotkeys. If your plugin does not use this feature, this function can be omitted.
  619.  * Hotkeys require ts3plugin_registerPluginID and ts3plugin_freeMemory to be implemented.
  620.  * This function is automatically called by the client after ts3plugin_init.
  621.  */
  622. void ts3plugin_initHotkeys(struct PluginHotkey*** hotkeys) {
  623.     /* Register hotkeys giving a keyword and a description.
  624.      * The keyword will be later passed to ts3plugin_onHotkeyEvent to identify which hotkey was triggered.
  625.      * The description is shown in the clients hotkey dialog. */
  626.     BEGIN_CREATE_HOTKEYS(3);  /* Create 3 hotkeys. Size must be correct for allocating memory. */
  627.     CREATE_HOTKEY("keyword_1", "Test hotkey 1");
  628.     CREATE_HOTKEY("keyword_2", "Test hotkey 2");
  629.     CREATE_HOTKEY("keyword_3", "Test hotkey 3");
  630.     END_CREATE_HOTKEYS;
  631.  
  632.     /* The client will call ts3plugin_freeMemory to release all allocated memory */
  633. }
  634.  
  635. /************************** TeamSpeak callbacks ***************************/
  636. /*
  637.  * Following functions are optional, feel free to remove unused callbacks.
  638.  * See the clientlib documentation for details on each function.
  639.  */
  640.  
  641. /* Clientlib */
  642.  
  643. void ts3plugin_onConnectStatusChangeEvent(uint64 serverConnectionHandlerID, int newStatus, unsigned int errorNumber) {
  644.     /* Some example code following to show how to use the information query functions. */
  645.  
  646.     if(newStatus == STATUS_CONNECTION_ESTABLISHED) {  /* connection established and we have client and channels available */
  647.         char* s;
  648.         char msg[1024];
  649.         anyID myID;
  650.         uint64* ids;
  651.         size_t i;
  652.         unsigned int error;
  653.  
  654.         /* Print clientlib version */
  655.         if(ts3Functions.getClientLibVersion(&s) == ERROR_ok) {
  656.             printf("PLUGIN: Client lib version: %s\n", s);
  657.             ts3Functions.freeMemory(s);  /* Release string */
  658.         } else {
  659.             ts3Functions.logMessage("Error querying client lib version", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  660.             return;
  661.         }
  662.  
  663.         /* Write plugin name and version to log */
  664.         snprintf(msg, sizeof(msg), "Plugin %s, Version %s, Author: %s", ts3plugin_name(), ts3plugin_version(), ts3plugin_author());
  665.         ts3Functions.logMessage(msg, LogLevel_INFO, "Plugin", serverConnectionHandlerID);
  666.  
  667.         /* Print virtual server name */
  668.         if((error = ts3Functions.getServerVariableAsString(serverConnectionHandlerID, VIRTUALSERVER_NAME, &s)) != ERROR_ok) {
  669.             if(error != ERROR_not_connected) {  /* Don't spam error in this case (failed to connect) */
  670.                 ts3Functions.logMessage("Error querying server name", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  671.             }
  672.             return;
  673.         }
  674.         printf("PLUGIN: Server name: %s\n", s);
  675.         ts3Functions.freeMemory(s);
  676.  
  677.         /* Print virtual server welcome message */
  678.         if(ts3Functions.getServerVariableAsString(serverConnectionHandlerID, VIRTUALSERVER_WELCOMEMESSAGE, &s) != ERROR_ok) {
  679.             ts3Functions.logMessage("Error querying server welcome message", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  680.             return;
  681.         }
  682.         printf("PLUGIN: Server welcome message: %s\n", s);
  683.         ts3Functions.freeMemory(s);  /* Release string */
  684.  
  685.         /* Print own client ID and nickname on this server */
  686.         if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) {
  687.             ts3Functions.logMessage("Error querying client ID", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  688.             return;
  689.         }
  690.         if(ts3Functions.getClientSelfVariableAsString(serverConnectionHandlerID, CLIENT_NICKNAME, &s) != ERROR_ok) {
  691.             ts3Functions.logMessage("Error querying client nickname", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  692.             return;
  693.         }
  694.         printf("PLUGIN: My client ID = %d, nickname = %s\n", myID, s);
  695.         ts3Functions.freeMemory(s);
  696.  
  697.         /* Print list of all channels on this server */
  698.         if(ts3Functions.getChannelList(serverConnectionHandlerID, &ids) != ERROR_ok) {
  699.             ts3Functions.logMessage("Error getting channel list", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  700.             return;
  701.         }
  702.         printf("PLUGIN: Available channels:\n");
  703.         for(i=0; ids[i]; i++) {
  704.             /* Query channel name */
  705.             if(ts3Functions.getChannelVariableAsString(serverConnectionHandlerID, ids[i], CHANNEL_NAME, &s) != ERROR_ok) {
  706.                 ts3Functions.logMessage("Error querying channel name", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  707.                 return;
  708.             }
  709.             printf("PLUGIN: Channel ID = %llu, name = %s\n", (long long unsigned int)ids[i], s);
  710.             ts3Functions.freeMemory(s);
  711.         }
  712.         ts3Functions.freeMemory(ids);  /* Release array */
  713.  
  714.         /* Print list of existing server connection handlers */
  715.         printf("PLUGIN: Existing server connection handlers:\n");
  716.         if(ts3Functions.getServerConnectionHandlerList(&ids) != ERROR_ok) {
  717.             ts3Functions.logMessage("Error getting server list", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  718.             return;
  719.         }
  720.         for(i=0; ids[i]; i++) {
  721.             if((error = ts3Functions.getServerVariableAsString(ids[i], VIRTUALSERVER_NAME, &s)) != ERROR_ok) {
  722.                 if(error != ERROR_not_connected) {  /* Don't spam error in this case (failed to connect) */
  723.                     ts3Functions.logMessage("Error querying server name", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  724.                 }
  725.                 continue;
  726.             }
  727.             printf("- %llu - %s\n", (long long unsigned int)ids[i], s);
  728.             ts3Functions.freeMemory(s);
  729.         }
  730.         ts3Functions.freeMemory(ids);
  731.     }
  732. }
  733.  
  734. void ts3plugin_onNewChannelEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 channelParentID) {
  735. }
  736.  
  737. void ts3plugin_onNewChannelCreatedEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 channelParentID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) {
  738. }
  739.  
  740. void ts3plugin_onDelChannelEvent(uint64 serverConnectionHandlerID, uint64 channelID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) {
  741. }
  742.  
  743. void ts3plugin_onChannelMoveEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 newChannelParentID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) {
  744. }
  745.  
  746. void ts3plugin_onUpdateChannelEvent(uint64 serverConnectionHandlerID, uint64 channelID) {
  747. }
  748.  
  749. void ts3plugin_onUpdateChannelEditedEvent(uint64 serverConnectionHandlerID, uint64 channelID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) {
  750. }
  751.  
  752. void ts3plugin_onUpdateClientEvent(uint64 serverConnectionHandlerID, anyID clientID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) {
  753. }
  754.  
  755. void ts3plugin_onClientMoveEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, const char* moveMessage) {
  756. }
  757.  
  758. void ts3plugin_onClientMoveSubscriptionEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility) {
  759. }
  760.  
  761. void ts3plugin_onClientMoveTimeoutEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, const char* timeoutMessage) {
  762. }
  763.  
  764. void ts3plugin_onClientMoveMovedEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID moverID, const char* moverName, const char* moverUniqueIdentifier, const char* moveMessage) {
  765. }
  766.  
  767. void ts3plugin_onClientKickFromChannelEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID kickerID, const char* kickerName, const char* kickerUniqueIdentifier, const char* kickMessage) {
  768. }
  769.  
  770. void ts3plugin_onClientKickFromServerEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID kickerID, const char* kickerName, const char* kickerUniqueIdentifier, const char* kickMessage) {
  771. }
  772.  
  773. void ts3plugin_onClientIDsEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, anyID clientID, const char* clientName) {
  774. }
  775.  
  776. void ts3plugin_onClientIDsFinishedEvent(uint64 serverConnectionHandlerID) {
  777. }
  778.  
  779. void ts3plugin_onServerEditedEvent(uint64 serverConnectionHandlerID, anyID editerID, const char* editerName, const char* editerUniqueIdentifier) {
  780. }
  781.  
  782. void ts3plugin_onServerUpdatedEvent(uint64 serverConnectionHandlerID) {
  783. }
  784.  
  785. int ts3plugin_onServerErrorEvent(uint64 serverConnectionHandlerID, const char* errorMessage, unsigned int error, const char* returnCode, const char* extraMessage) {
  786.     printf("PLUGIN: onServerErrorEvent %llu %s %d %s\n", (long long unsigned int)serverConnectionHandlerID, errorMessage, error, (returnCode ? returnCode : ""));
  787.     if(returnCode) {
  788.         /* A plugin could now check the returnCode with previously (when calling a function) remembered returnCodes and react accordingly */
  789.         /* In case of using a a plugin return code, the plugin can return:
  790.          * 0: Client will continue handling this error (print to chat tab)
  791.          * 1: Client will ignore this error, the plugin announces it has handled it */
  792.         return 1;
  793.     }
  794.     return 0;  /* If no plugin return code was used, the return value of this function is ignored */
  795. }
  796.  
  797. void ts3plugin_onServerStopEvent(uint64 serverConnectionHandlerID, const char* shutdownMessage) {
  798. }
  799.  
  800. int ts3plugin_onTextMessageEvent(uint64 serverConnectionHandlerID, anyID targetMode, anyID toID, anyID fromID, const char* fromName, const char* fromUniqueIdentifier, const char* message, int ffIgnored) {
  801.     printf("PLUGIN: onTextMessageEvent %llu %d %d %s %s %d\n", (long long unsigned int)serverConnectionHandlerID, targetMode, fromID, fromName, message, ffIgnored);
  802.  
  803.     /* Friend/Foe manager has ignored the message, so ignore here as well. */
  804.     if(ffIgnored) {
  805.         return 0; /* Client will ignore the message anyways, so return value here doesn't matter */
  806.     }
  807.  
  808. #if 0
  809.     {
  810.         /* Example code: Autoreply to sender */
  811.         /* Disabled because quite annoying, but should give you some ideas what is possible here */
  812.         /* Careful, when two clients use this, they will get banned quickly... */
  813.         anyID myID;
  814.         if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) {
  815.             ts3Functions.logMessage("Error querying own client id", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  816.             return 0;
  817.         }
  818.         if(fromID != myID) {  /* Don't reply when source is own client */
  819.             if(ts3Functions.requestSendPrivateTextMsg(serverConnectionHandlerID, "Text message back!", fromID, NULL) != ERROR_ok) {
  820.                 ts3Functions.logMessage("Error requesting send text message", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  821.             }
  822.         }
  823.     }
  824. #endif
  825.  
  826.     return 0;  /* 0 = handle normally, 1 = client will ignore the text message */
  827. }
  828.  
  829. void ts3plugin_onTalkStatusChangeEvent(uint64 serverConnectionHandlerID, int status, int isReceivedWhisper, anyID clientID) {
  830.     /* Demonstrate usage of getClientDisplayName */
  831.     char name[512];
  832.     if(ts3Functions.getClientDisplayName(serverConnectionHandlerID, clientID, name, 512) == ERROR_ok) {
  833.         if(status == STATUS_TALKING) {
  834.             printf("--> %s starts talking\n", name);
  835.         } else {
  836.             printf("--> %s stops talking\n", name);
  837.         }
  838.     }
  839. }
  840.  
  841. void ts3plugin_onConnectionInfoEvent(uint64 serverConnectionHandlerID, anyID clientID) {
  842. }
  843.  
  844. void ts3plugin_onServerConnectionInfoEvent(uint64 serverConnectionHandlerID) {
  845. }
  846.  
  847. void ts3plugin_onChannelSubscribeEvent(uint64 serverConnectionHandlerID, uint64 channelID) {
  848. }
  849.  
  850. void ts3plugin_onChannelSubscribeFinishedEvent(uint64 serverConnectionHandlerID) {
  851. }
  852.  
  853. void ts3plugin_onChannelUnsubscribeEvent(uint64 serverConnectionHandlerID, uint64 channelID) {
  854. }
  855.  
  856. void ts3plugin_onChannelUnsubscribeFinishedEvent(uint64 serverConnectionHandlerID) {
  857. }
  858.  
  859. void ts3plugin_onChannelDescriptionUpdateEvent(uint64 serverConnectionHandlerID, uint64 channelID) {
  860. }
  861.  
  862. void ts3plugin_onChannelPasswordChangedEvent(uint64 serverConnectionHandlerID, uint64 channelID) {
  863. }
  864.  
  865. void ts3plugin_onPlaybackShutdownCompleteEvent(uint64 serverConnectionHandlerID) {
  866. }
  867.  
  868. void ts3plugin_onSoundDeviceListChangedEvent(const char* modeID, int playOrCap) {
  869. }
  870.  
  871. void ts3plugin_onEditPlaybackVoiceDataEvent(uint64 serverConnectionHandlerID, anyID clientID, short* samples, int sampleCount, int channels) {
  872. }
  873.  
  874. void ts3plugin_onEditPostProcessVoiceDataEvent(uint64 serverConnectionHandlerID, anyID clientID, short* samples, int sampleCount, int channels, const unsigned int* channelSpeakerArray, unsigned int* channelFillMask) {
  875. }
  876.  
  877. void ts3plugin_onEditMixedPlaybackVoiceDataEvent(uint64 serverConnectionHandlerID, short* samples, int sampleCount, int channels, const unsigned int* channelSpeakerArray, unsigned int* channelFillMask) {
  878. }
  879.  
  880. void ts3plugin_onEditCapturedVoiceDataEvent(uint64 serverConnectionHandlerID, short* samples, int sampleCount, int channels, int* edited) {
  881. }
  882.  
  883. void ts3plugin_onCustom3dRolloffCalculationClientEvent(uint64 serverConnectionHandlerID, anyID clientID, float distance, float* volume) {
  884. }
  885.  
  886. void ts3plugin_onCustom3dRolloffCalculationWaveEvent(uint64 serverConnectionHandlerID, uint64 waveHandle, float distance, float* volume) {
  887. }
  888.  
  889. void ts3plugin_onUserLoggingMessageEvent(const char* logMessage, int logLevel, const char* logChannel, uint64 logID, const char* logTime, const char* completeLogString) {
  890. }
  891.  
  892. /* Clientlib rare */
  893.  
  894. 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) {
  895. }
  896.  
  897. int ts3plugin_onClientPokeEvent(uint64 serverConnectionHandlerID, anyID fromClientID, const char* pokerName, const char* pokerUniqueIdentity, const char* message, int ffIgnored) {
  898.     anyID myID;
  899.  
  900.     printf("PLUGIN onClientPokeEvent: %llu %d %s %s %d\n", (long long unsigned int)serverConnectionHandlerID, fromClientID, pokerName, message, ffIgnored);
  901.  
  902.     /* Check if the Friend/Foe manager has already blocked this poke */
  903.     if(ffIgnored) {
  904.         return 0;  /* Client will block anyways, doesn't matter what we return */
  905.     }
  906.  
  907.     /* Example code: Send text message back to poking client */
  908.     if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) {  /* Get own client ID */
  909.         ts3Functions.logMessage("Error querying own client id", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  910.         return 0;
  911.     }
  912.     if(fromClientID != myID) {  /* Don't reply when source is own client */
  913.         if(ts3Functions.requestSendPrivateTextMsg(serverConnectionHandlerID, "Received your poke!", fromClientID, NULL) != ERROR_ok) {
  914.             ts3Functions.logMessage("Error requesting send text message", LogLevel_ERROR, "Plugin", serverConnectionHandlerID);
  915.         }
  916.     }
  917.  
  918.     return 0;  /* 0 = handle normally, 1 = client will ignore the poke */
  919. }
  920.  
  921. void ts3plugin_onClientSelfVariableUpdateEvent(uint64 serverConnectionHandlerID, int flag, const char* oldValue, const char* newValue) {
  922. }
  923.  
  924. void ts3plugin_onFileListEvent(uint64 serverConnectionHandlerID, uint64 channelID, const char* path, const char* name, uint64 size, uint64 datetime, int type, uint64 incompletesize, const char* returnCode) {
  925. }
  926.  
  927. void ts3plugin_onFileListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelID, const char* path) {
  928. }
  929.  
  930. void ts3plugin_onFileInfoEvent(uint64 serverConnectionHandlerID, uint64 channelID, const char* name, uint64 size, uint64 datetime) {
  931. }
  932.  
  933. void ts3plugin_onServerGroupListEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID, const char* name, int type, int iconID, int saveDB) {
  934. }
  935.  
  936. void ts3plugin_onServerGroupListFinishedEvent(uint64 serverConnectionHandlerID) {
  937. }
  938.  
  939. void ts3plugin_onServerGroupByClientIDEvent(uint64 serverConnectionHandlerID, const char* name, uint64 serverGroupList, uint64 clientDatabaseID) {
  940. }
  941.  
  942. void ts3plugin_onServerGroupPermListEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) {
  943. }
  944.  
  945. void ts3plugin_onServerGroupPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID) {
  946. }
  947.  
  948. void ts3plugin_onServerGroupClientListEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID, uint64 clientDatabaseID, const char* clientNameIdentifier, const char* clientUniqueID) {
  949. }
  950.  
  951. void ts3plugin_onChannelGroupListEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID, const char* name, int type, int iconID, int saveDB) {
  952. }
  953.  
  954. void ts3plugin_onChannelGroupListFinishedEvent(uint64 serverConnectionHandlerID) {
  955. }
  956.  
  957. void ts3plugin_onChannelGroupPermListEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) {
  958. }
  959.  
  960. void ts3plugin_onChannelGroupPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID) {
  961. }
  962.  
  963. void ts3plugin_onChannelPermListEvent(uint64 serverConnectionHandlerID, uint64 channelID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) {
  964. }
  965.  
  966. void ts3plugin_onChannelPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelID) {
  967. }
  968.  
  969. void ts3plugin_onClientPermListEvent(uint64 serverConnectionHandlerID, uint64 clientDatabaseID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) {
  970. }
  971.  
  972. void ts3plugin_onClientPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 clientDatabaseID) {
  973. }
  974.  
  975. void ts3plugin_onChannelClientPermListEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 clientDatabaseID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) {
  976. }
  977.  
  978. void ts3plugin_onChannelClientPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 clientDatabaseID) {
  979. }
  980.  
  981. void ts3plugin_onClientChannelGroupChangedEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID, uint64 channelID, anyID clientID, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity) {
  982. }
  983.  
  984. int ts3plugin_onServerPermissionErrorEvent(uint64 serverConnectionHandlerID, const char* errorMessage, unsigned int error, const char* returnCode, unsigned int failedPermissionID) {
  985.     return 0;  /* See onServerErrorEvent for return code description */
  986. }
  987.  
  988. void ts3plugin_onPermissionListGroupEndIDEvent(uint64 serverConnectionHandlerID, unsigned int groupEndID) {
  989. }
  990.  
  991. void ts3plugin_onPermissionListEvent(uint64 serverConnectionHandlerID, unsigned int permissionID, const char* permissionName, const char* permissionDescription) {
  992. }
  993.  
  994. void ts3plugin_onPermissionListFinishedEvent(uint64 serverConnectionHandlerID) {
  995. }
  996.  
  997. void ts3plugin_onPermissionOverviewEvent(uint64 serverConnectionHandlerID, uint64 clientDatabaseID, uint64 channelID, int overviewType, uint64 overviewID1, uint64 overviewID2, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) {
  998. }
  999.  
  1000. void ts3plugin_onPermissionOverviewFinishedEvent(uint64 serverConnectionHandlerID) {
  1001. }
  1002.  
  1003. void ts3plugin_onServerGroupClientAddedEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientName, const char* clientUniqueIdentity, uint64 serverGroupID, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity) {
  1004. }
  1005.  
  1006. void ts3plugin_onServerGroupClientDeletedEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientName, const char* clientUniqueIdentity, uint64 serverGroupID, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity) {
  1007. }
  1008.  
  1009. void ts3plugin_onClientNeededPermissionsEvent(uint64 serverConnectionHandlerID, unsigned int permissionID, int permissionValue) {
  1010. }
  1011.  
  1012. void ts3plugin_onClientNeededPermissionsFinishedEvent(uint64 serverConnectionHandlerID) {
  1013. }
  1014.  
  1015. void ts3plugin_onFileTransferStatusEvent(anyID transferID, unsigned int status, const char* statusMessage, uint64 remotefileSize, uint64 serverConnectionHandlerID) {
  1016. }
  1017.  
  1018. void ts3plugin_onClientChatClosedEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientUniqueIdentity) {
  1019. }
  1020.  
  1021. void ts3plugin_onClientChatComposingEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientUniqueIdentity) {
  1022. }
  1023.  
  1024. void ts3plugin_onServerLogEvent(uint64 serverConnectionHandlerID, const char* logMsg) {
  1025. }
  1026.  
  1027. void ts3plugin_onServerLogFinishedEvent(uint64 serverConnectionHandlerID, uint64 lastPos, uint64 fileSize) {
  1028. }
  1029.  
  1030. void ts3plugin_onMessageListEvent(uint64 serverConnectionHandlerID, uint64 messageID, const char* fromClientUniqueIdentity, const char* subject, uint64 timestamp, int flagRead) {
  1031. }
  1032.  
  1033. void ts3plugin_onMessageGetEvent(uint64 serverConnectionHandlerID, uint64 messageID, const char* fromClientUniqueIdentity, const char* subject, const char* message, uint64 timestamp) {
  1034. }
  1035.  
  1036. void ts3plugin_onClientDBIDfromUIDEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, uint64 clientDatabaseID) {
  1037. }
  1038.  
  1039. void ts3plugin_onClientNamefromUIDEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, uint64 clientDatabaseID, const char* clientNickName) {
  1040. }
  1041.  
  1042. void ts3plugin_onClientNamefromDBIDEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, uint64 clientDatabaseID, const char* clientNickName) {
  1043. }
  1044.  
  1045. void ts3plugin_onComplainListEvent(uint64 serverConnectionHandlerID, uint64 targetClientDatabaseID, const char* targetClientNickName, uint64 fromClientDatabaseID, const char* fromClientNickName, const char* complainReason, uint64 timestamp) {
  1046. }
  1047.  
  1048. void ts3plugin_onBanListEvent(uint64 serverConnectionHandlerID, uint64 banid, const char* ip, const char* name, const char* uid, uint64 creationTime, uint64 durationTime, const char* invokerName,
  1049.                               uint64 invokercldbid, const char* invokeruid, const char* reason, int numberOfEnforcements, const char* lastNickName) {
  1050. }
  1051.  
  1052. void ts3plugin_onClientServerQueryLoginPasswordEvent(uint64 serverConnectionHandlerID, const char* loginPassword) {
  1053. }
  1054.  
  1055. void ts3plugin_onPluginCommandEvent(uint64 serverConnectionHandlerID, const char* pluginName, const char* pluginCommand) {
  1056.     printf("ON PLUGIN COMMAND: %s %s\n", pluginName, pluginCommand);
  1057. }
  1058.  
  1059. void ts3plugin_onIncomingClientQueryEvent(uint64 serverConnectionHandlerID, const char* commandText) {
  1060. }
  1061.  
  1062. 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) {
  1063. }
  1064.  
  1065. /* Client UI callbacks */
  1066.  
  1067. /*
  1068.  * Called from client when an avatar image has been downloaded to or deleted from cache.
  1069.  * This callback can be called spontaneously or in response to ts3Functions.getAvatar()
  1070.  */
  1071. void ts3plugin_onAvatarUpdated(uint64 serverConnectionHandlerID, anyID clientID, const char* avatarPath) {
  1072.     /* If avatarPath is NULL, the avatar got deleted */
  1073.     /* If not NULL, avatarPath contains the path to the avatar file in the TS3Client cache */
  1074.     if(avatarPath != NULL) {
  1075.         printf("onAvatarUpdated: %llu %d %s\n", (long long unsigned int)serverConnectionHandlerID, clientID, avatarPath);
  1076.     } else {
  1077.         printf("onAvatarUpdated: %llu %d - deleted\n", (long long unsigned int)serverConnectionHandlerID, clientID);
  1078.     }
  1079. }
  1080.  
  1081. /*
  1082.  * Called when a plugin menu item (see ts3plugin_initMenus) is triggered. Optional function, when not using plugin menus, do not implement this.
  1083.  *
  1084.  * Parameters:
  1085.  * - serverConnectionHandlerID: ID of the current server tab
  1086.  * - type: Type of the menu (PLUGIN_MENU_TYPE_CHANNEL, PLUGIN_MENU_TYPE_CLIENT or PLUGIN_MENU_TYPE_GLOBAL)
  1087.  * - menuItemID: Id used when creating the menu item
  1088.  * - selectedItemID: Channel or Client ID in the case of PLUGIN_MENU_TYPE_CHANNEL and PLUGIN_MENU_TYPE_CLIENT. 0 for PLUGIN_MENU_TYPE_GLOBAL.
  1089.  */
  1090. void ts3plugin_onMenuItemEvent(uint64 serverConnectionHandlerID, enum PluginMenuType type, int menuItemID, uint64 selectedItemID) {
  1091.     printf("PLUGIN: onMenuItemEvent: serverConnectionHandlerID=%llu, type=%d, menuItemID=%d, selectedItemID=%llu\n", (long long unsigned int)serverConnectionHandlerID, type, menuItemID, (long long unsigned int)selectedItemID);
  1092.     switch(type) {
  1093.         case PLUGIN_MENU_TYPE_GLOBAL:
  1094.             /* Global menu item was triggered. selectedItemID is unused and set to zero. */
  1095.             switch(menuItemID) {
  1096.                 case MENU_ID_GLOBAL_1:
  1097.                     /* Menu global 1 was triggered */
  1098.                     break;
  1099.                 case MENU_ID_GLOBAL_2:
  1100.                     /* Menu global 2 was triggered */
  1101.                     break;
  1102.                 default:
  1103.                     break;
  1104.             }
  1105.             break;
  1106.         case PLUGIN_MENU_TYPE_CHANNEL:
  1107.             /* Channel contextmenu item was triggered. selectedItemID is the channelID of the selected channel */
  1108.             switch(menuItemID) {
  1109.                 case MENU_ID_CHANNEL_1:
  1110.                     /* Menu channel 1 was triggered */
  1111.                     break;
  1112.                 case MENU_ID_CHANNEL_2:
  1113.                     /* Menu channel 2 was triggered */
  1114.                     break;
  1115.                 case MENU_ID_CHANNEL_3:
  1116.                     /* Menu channel 3 was triggered */
  1117.                     break;
  1118.                 default:
  1119.                     break;
  1120.             }
  1121.             break;
  1122.         case PLUGIN_MENU_TYPE_CLIENT:
  1123.             /* Client contextmenu item was triggered. selectedItemID is the clientID of the selected client */
  1124.             switch(menuItemID) {
  1125.                 case MENU_ID_CLIENT_1:
  1126.                     /* Menu client 1 was triggered */
  1127.                     break;
  1128.                 case MENU_ID_CLIENT_2:
  1129.                     /* Menu client 2 was triggered */
  1130.                     break;
  1131.                 default:
  1132.                     break;
  1133.             }
  1134.             break;
  1135.         default:
  1136.             break;
  1137.     }
  1138. }
  1139.  
  1140. /* This function is called if a plugin hotkey was pressed. Omit if hotkeys are unused. */
  1141. void ts3plugin_onHotkeyEvent(const char* keyword) {
  1142.     printf("PLUGIN: Hotkey event: %s\n", keyword);
  1143.     /* Identify the hotkey by keyword ("keyword_1", "keyword_2" or "keyword_3" in this example) and handle here... */
  1144. }
  1145.  
  1146. /* Called when recording a hotkey has finished after calling ts3Functions.requestHotkeyInputDialog */
  1147. void ts3plugin_onHotkeyRecordedEvent(const char* keyword, const char* key) {
  1148. }
  1149.  
  1150. // This function receives your key Identifier you send to notifyKeyEvent and should return
  1151. // the friendly device name of the device this hotkey originates from. Used for display in UI.
  1152. const char* ts3plugin_keyDeviceName(const char* keyIdentifier) {
  1153.     return NULL;
  1154. }
  1155.  
  1156. // This function translates the given key identifier to a friendly key name for display in the UI
  1157. const char* ts3plugin_displayKeyText(const char* keyIdentifier) {
  1158.     return NULL;
  1159. }
  1160.  
  1161. // This is used internally as a prefix for hotkeys so we can store them without collisions.
  1162. // Should be unique across plugins.
  1163. const char* ts3plugin_keyPrefix() {
  1164.     return NULL;
  1165. }
  1166.  
  1167. /* Called when client custom nickname changed */
  1168. void ts3plugin_onClientDisplayNameChanged(uint64 serverConnectionHandlerID, anyID clientID, const char* displayName, const char* uniqueClientIdentifier) {
  1169. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top