/* * TeamSpeak SDK server creation params sample * * Copyright (c) TeamSpeak-Systems */ #ifdef _WINDOWS #define _CRT_SECURE_NO_WARNINGS #include #else #include #include #include #endif #include #include #include #include #include #include "id_io.h" #define DEFAULT_VIRTUAL_SERVER_ID 1 /* Maximum number of clients allowed per virtual server */ #define MAX_CLIENTS 8 #ifdef _WINDOWS #define SLEEP(x) Sleep(x) #else #define SLEEP(x) usleep(x*1000) #endif #define CHECK_ERROR(x) if((error = x) != ERROR_ok) { goto on_error; } /* * Callback when client has connected. * * Parameter: * serverID - Virtual server ID * clientID - ID of connected client * channelID - ID of channel the client joined */ void onClientConnected(uint64 serverID, anyID clientID, uint64 channelID, unsigned int* removeClientError) { char* clientName; unsigned int error; /* Query client nickname */ if((error = ts3server_getClientVariableAsString(serverID, clientID, CLIENT_NICKNAME, &clientName)) != ERROR_ok) { char* errormsg; if(ts3server_getGlobalErrorMessage(error, &errormsg) == ERROR_ok) { printf("Error querying client nickname: %s\n", errormsg); ts3server_freeMemory(errormsg); } return; } printf("Client '%s' joined channel %llu on virtual server %llu\n", clientName, (unsigned long long) channelID, (unsigned long long)serverID); } /* * Callback when client has disconnected. * * Parameter: * serverID - Virtual server ID * clientID - ID of disconnected client * channelID - ID of channel the client left */ void onClientDisconnected(uint64 serverID, anyID clientID, uint64 channelID) { printf("Client %u left channel %llu on virtual server %llu\n", clientID, (unsigned long long)channelID, (unsigned long long)serverID); } /* * Callback when client has moved. * * Parameter: * serverID - Virtual server ID * clientID - ID of moved client * oldChannelID - ID of old channel the client left * newChannelID - ID of new channel the client joined */ void onClientMoved(uint64 serverID, anyID clientID, uint64 oldChannelID, uint64 newChannelID) { printf("Client %u moved from channel %llu to channel %llu on virtual server %llu\n", clientID, (unsigned long long)oldChannelID, (unsigned long long)newChannelID, (unsigned long long)serverID); } /* * Callback when channel has been created. * * Parameter: * serverID - Virtual server ID * invokerClientID - ID of the client who created the channel * channelID - ID of the created channel */ void onChannelCreated(uint64 serverID, anyID invokerClientID, uint64 channelID) { printf("Channel %llu created by %u on virtual server %llu\n", (unsigned long long)channelID, invokerClientID, (unsigned long long)serverID); } /* * Callback when channel has been edited. * * Parameter: * serverID - Virtual server ID * invokerClientID - ID of the client who edited the channel * channelID - ID of the edited channel */ void onChannelEdited(uint64 serverID, anyID invokerClientID, uint64 channelID) { printf("Channel %llu edited by %u on virtual server %llu\n", (unsigned long long)channelID, invokerClientID, (unsigned long long)serverID); } /* * Callback when channel has been deleted. * * Parameter: * serverID - Virtual server ID * invokerClientID - ID of the client who deleted the channel * channelID - ID of the deleted channel */ void onChannelDeleted(uint64 serverID, anyID invokerClientID, uint64 channelID) { printf("Channel %llu deleted by %u on virtual server %llu\n", (unsigned long long)channelID, invokerClientID, (unsigned long long)serverID); } void showHelp() { printf("\n[q] - Quit\n[h] - Show this help\n[v] - List virtual servers\n[c] - Show channels of virtual server %d\n", DEFAULT_VIRTUAL_SERVER_ID); printf("[l] - Show clients of virtual server %d\n[n] - Create new channel on virtual server %d with generated name\n[N] - Create new channel on virtual server %d with custom name\n", DEFAULT_VIRTUAL_SERVER_ID, DEFAULT_VIRTUAL_SERVER_ID, DEFAULT_VIRTUAL_SERVER_ID); printf("[d] - Delete channel on virtual server %d\n\n", DEFAULT_VIRTUAL_SERVER_ID); printf("[C] - Create new virtual server\n[E] - Edit virtual server\n[S] - Stop virtual server\n\n"); } void emptyInputBuffer() { int c; while((c = getchar()) != '\n' && c != EOF); } void showVirtualServers() { uint64* ids; int i; unsigned int error; printf("\nList of virtual servers:\n"); if((error = ts3server_getVirtualServerList(&ids)) != ERROR_ok) { /* Get array of virtual server IDs */ printf("Error getting virtual server list: %d\n", error); return; } if(!ids[0]) { printf("No virtual servers\n\n"); ts3server_freeMemory(ids); return; } for(i=0; ids[i]; i++) { char* name; int slotCount; char* virtualServerUniqueIdentifier; if((error = ts3server_getVirtualServerVariableAsString(ids[i], VIRTUALSERVER_NAME, &name)) != ERROR_ok) { /* Query server name */ printf("Error getting virtual server nickname: %d\n", error); break; } if((error = ts3server_getVirtualServerVariableAsInt(ids[i], VIRTUALSERVER_MAXCLIENTS, &slotCount)) != ERROR_ok) { printf("Error getting virtual server slot count: %d\n", error); break; } if((error = ts3server_getVirtualServerVariableAsString(ids[i], VIRTUALSERVER_UNIQUE_IDENTIFIER, &virtualServerUniqueIdentifier)) != ERROR_ok) { printf("Error getting virtual server unique identifier: %d\n", error); break; } printf("ID=%llu NAME=\"%s\" CAPACITY=%d Unique Identifier=\"%s\"\n", (unsigned long long)ids[i], name, slotCount, virtualServerUniqueIdentifier); ts3server_freeMemory(name); /* Do not free memory if above function returned an error */ ts3server_freeMemory(virtualServerUniqueIdentifier); } printf("\n"); ts3server_freeMemory(ids); /* Release array */ } void showChannels(uint64 serverID) { uint64* ids; int i; unsigned int error; printf("\nList of channels on virtual server %llu:\n", (unsigned long long)serverID); if((error = ts3server_getChannelList(serverID, &ids)) != ERROR_ok) { /* Get array of channel IDs */ printf("Error getting channel list: %d\n", error); return; } if(!ids[0]) { printf("No channels\n\n"); ts3server_freeMemory(ids); return; } for(i=0; ids[i]; i++) { char* name; if((error = ts3server_getChannelVariableAsString(serverID, ids[i], CHANNEL_NAME, &name)) != ERROR_ok) { /* Query channel name */ printf("Error querying channel name: %d\n", error); break; } printf("%llu - %s\n", (unsigned long long)ids[i], name); ts3server_freeMemory(name); /* Do not free memory if above function returned an error */ } printf("\n"); ts3server_freeMemory(ids); /* Release array */ } void showClients(uint64 serverID) { anyID* ids; int i; unsigned int error; printf("\nList of clients on virtual server %llu:\n", (unsigned long long)serverID); if((error = ts3server_getClientList(serverID, &ids)) != ERROR_ok) { /* Get array of client IDs */ printf("Error getting client list: %d\n", error); return; } if(!ids[0]) { printf("No clients\n\n"); ts3server_freeMemory(ids); return; } for(i=0; ids[i]; i++) { char* name; if((error = ts3server_getClientVariableAsString(serverID, ids[i], CLIENT_NICKNAME, &name)) != ERROR_ok) { /* Query client nickname */ printf("Error querying client nickname: %d\n", error); break; } printf("%u - %s\n", ids[i], name); ts3server_freeMemory(name); /* Do not free memory if above function returned an error */ } printf("\n"); ts3server_freeMemory(ids); /* Release array */ } void createDefaultChannelName(char *name) { static int i = 11; /* We already have 10 channels in this example */ sprintf(name, "Channel_%d", i++); } void enterName(char *name) { char *s; printf("\nEnter name: "); fgets(name, BUFSIZ, stdin); s = strrchr(name, '\n'); if(s) { *s = '\0'; } } void createChannel(uint64 serverID, const char *name) { /* This code demonstrates how to use the new createChannel API. */ unsigned int error; uint64 newChannelID; struct TS3ChannelCreationParams* ccp; struct TS3Variables* vars; /* Create a new struct channel parameters struct. Memory is allocated in the clientlib, * so the struct needs to be freed using ts3server_freeMemory when done */ error = ts3server_makeChannelCreationParams(&ccp); if(error != ERROR_ok) { printf("Failed to make channel creation params: %d\n", error); goto leave; } /* Set essential channel paramters: * parentID 0 -> create as top-level channel * channelID 0 -> server will automatically assign a new channel ID. An existing channel ID would be an error */ error = ts3server_setChannelCreationParams(ccp, 0, 0); if(error != ERROR_ok) { printf("Failed to set channel creation params: %d\n", error); goto leave; } /* Query a struct TS3Variables, used to set additional parameters below */ error = ts3server_getChannelCreationParamsVariables(ccp, &vars); if(error != ERROR_ok) { printf("Failed to get variables from channel creation params: %d\n", error); goto leave; } /* Use above queried struct TS3Variables to set additional channel parameters */ /* Set codec quality */ error = ts3server_setVariableAsInt(vars, CHANNEL_CODEC_QUALITY, 10); if (error != ERROR_ok) { printf("Error setting channel quality: %d", error); goto leave; } /* Set channel name */ error = ts3server_setVariableAsString(vars, CHANNEL_NAME, name); if(error != ERROR_ok) { printf("Failed to set channel name: %d\n", error); goto leave; } /* Make channel permanent (important, otherwise the empty channel would be immediately deleted after creation) */ error = ts3server_setVariableAsInt(vars, CHANNEL_FLAG_PERMANENT, 1); if(error != ERROR_ok) { printf("Failed to set channel name: %d\n", error); goto leave; } /* Set channel topic */ error = ts3server_setVariableAsString(vars, CHANNEL_TOPIC, "My topic"); if(error != ERROR_ok) { printf("Failed to set channel topic: %d\n", error); goto leave; } /* Finally create the channel. Write the ID of the created channel into newChannelID */ error = ts3server_createChannel(serverID, ccp, CHANNEL_CREATE_FLAG_NONE, &newChannelID); if(error != ERROR_ok) { printf("Failed to create channel: %d\n", error); goto leave; } printf("\nCreated channel: %llu\n\n", (unsigned long long)newChannelID); leave: /* Cleanup struct TS3ChannelCreationParams */ ts3server_freeMemory(ccp); } void deleteChannel(uint64 serverID) { uint64 channelID; int n; unsigned int error; /* Query channel ID from user */ printf("\nEnter ID of channel to delete: "); n = scanf("%llu", (unsigned long long*)&channelID); emptyInputBuffer(); if(n == 0) { printf("Invalid input. Please enter a number.\n\n"); return; } /* Delete channel */ if((error = ts3server_channelDelete(serverID, channelID, 0)) != ERROR_ok) { char* errormsg; if(ts3server_getGlobalErrorMessage(error, &errormsg) == ERROR_ok) { printf("Error deleting channel: %s\n\n", errormsg); ts3server_freeMemory(errormsg); } } } void renameChannel(uint64 serverID) { uint64 channelID; int n; unsigned int error; char name[BUFSIZ]; /* Query channel ID from user */ printf("\nEnter ID of channel to rename: "); n = scanf("%llu", (unsigned long long*)&channelID); emptyInputBuffer(); if(n == 0) { printf("Invalid input. Please enter a number.\n\n"); return; } /* Query new channel name from user */ enterName(name); /* Change channel name and flush changes */ CHECK_ERROR(ts3server_setChannelVariableAsString(serverID, channelID, CHANNEL_NAME, name)); CHECK_ERROR(ts3server_flushChannelVariable(serverID, channelID)); printf("Renamed channel %llu\n\n", (unsigned long long)channelID); return; on_error: printf("Error renaming channel: %d\n\n", error); } void moveClient(uint64 serverID) { anyID clientIDArray[2]; /* We only want to move one client plus terminating null end-marker */ uint64 newChannelID; /* ID of channel to move the client into */ unsigned int error; int n; /* Query client ID from user */ printf("\nEnter ID of client to move: "); n = scanf("%hu", &clientIDArray[0]); emptyInputBuffer(); if(n == 0) { printf("Invalid input. Please enter a number.\n\n"); return; } clientIDArray[1] = 0; /* Add end-marker */ /* Query channel ID from user */ printf("\nEnter ID of channel to move client into: "); n = scanf("%llu", (unsigned long long*)&newChannelID); emptyInputBuffer(); if(n == 0) { printf("Invalid input. Please enter a number.\n\n"); return; } /* Move client and check for error */ if((error = ts3server_clientMove(serverID, newChannelID, clientIDArray)) != ERROR_ok) { char* errormsg; if(ts3server_getGlobalErrorMessage(error, &errormsg) == ERROR_ok) { printf("Error moving client: %s\n\n", errormsg); ts3server_freeMemory(errormsg); } return; } printf("Client %d moved to channel %llu\n", clientIDArray[0], (unsigned long long)newChannelID); } /* Shows how to use the new server params method to create a virtual server */ uint64 createVirtualServer2(const char* name, int port, unsigned int maxClients) { char buffer[BUFSIZ] = { 0 }; char filename[BUFSIZ]; char port_str[20]; char* keyPair; unsigned int error; int i; struct TS3VirtualServerCreationParams* vscp; struct TS3ChannelCreationParams* ccp; struct TS3Variables* vars; uint64 serverID = 0; /* Assemble filename: keypair_.txt */ strcpy(filename, "keypair_"); sprintf(port_str, "%d", port); strcat(filename, port_str); strcat(filename, ".txt"); /* Try reading keyPair from file */ if(readKeyPairFromFile(filename, buffer) == 0) { keyPair = buffer; /* Id read from file */ } else { keyPair = ""; /* No Id saved, start virtual server with empty keyPair string */ } /* Create server creation params, write result into empty struct TS3VirtualServerCreationParams */ error = ts3server_makeVirtualServerCreationParams(&vscp); if(error != ERROR_ok) { printf("Error during makeVirtualServerCreationParams: %d\n", error); return 0; } /* Set essential connection data to server creation params: * port 9987, ip NULL (localhost), server keypair, max clients, channel count, virtual server ID */ error = ts3server_setVirtualServerCreationParams(vscp, port, NULL, keyPair, maxClients, 10, 1); if(error != ERROR_ok) { printf("Error during setVirtualServerCreationParams: %d\n", error); goto leave; } /* Query the struct TS3Variables from the server creation params, to set some additional parameters */ error = ts3server_getVirtualServerCreationParamsVariables(vscp, &vars); if(error != ERROR_ok) { printf("Error during getVirtualServerCreationParamsVariables: %d\n", error); goto leave; } /* Below we write some additional server parameters into the struct TS3Variables. * These parameters are not part of the essential parameters, which we defined earlier * in ts3server_setVirtualServerCreationParams */ /* Set virtual server name */ error = ts3server_setVariableAsString(vars, VIRTUALSERVER_NAME, "TeamSpeak3 SDK Server"); if(error != ERROR_ok) { printf("Error setting server name: %d\n", error); goto leave; } /* Set virtual server password */ error = ts3server_setVariableAsString(vars, VIRTUALSERVER_PASSWORD, "secret"); if(error != ERROR_ok) { printf("Error setting server password: %d\n", error); goto leave; } /* Create 10 channels, write them into the struct channel params, which we queried earlier */ for(i = 0; i < 10; ++i) { /* Get the channel creation param for the channel index. This channel param structs are subobjects * created inside the server creation params. * The number of available channel params depends on the number of channels set above in * ts3server_setVirtualServerCreationParams (10 in this sample) * Write result into the reused struct TS3ChannelCreationParams. */ error = ts3server_getVirtualServerCreationParamsChannelCreationParams(vscp, i, &ccp); if(error != ERROR_ok) { printf("Error during getVirtualServerCreationParamsChannelCreationParams: %d\n", error); goto leave; } /* Now fill the struct channel creation params with some channel data */ /* Set essential data: channel parent ID and channel ID. * The idea here is to be able to restore a previously saved channel structure keeping the * same channel ID over server restarts. If we would create channels the old way, it would not * be possible to guarantee the channelID, as it would be assigned automatically by the server. * Basically this allows to recreate snapshots of the channel tree. */ error = ts3server_setChannelCreationParams(ccp, 0, i + 1); if(error != ERROR_ok) { printf("Error during setChannelCreationParams: %d\n", error); goto leave; } /* As above with the server, query a TS3Variables (reused) for this channel, which we * can fill with some additional parameters that are not part of the essentials */ error = ts3server_getChannelCreationParamsVariables(ccp, &vars); if(error != ERROR_ok) { printf("Error during getChannelCreationParamsVariables: %d\n", error); goto leave; } /* Now fill the queried struct TS3Variables with additional parameters */ /* Make first channel default */ if(i == 0) { error = ts3server_setVariableAsInt(vars, CHANNEL_FLAG_DEFAULT, 1); if(error != ERROR_ok) { printf("Error setting channel %d default: %d", (i + 1), error); goto leave; } } /* Set codec quality */ error = ts3server_setVariableAsInt(vars, CHANNEL_CODEC_QUALITY, 10); if (error != ERROR_ok) { printf("Error setting channel quality: %d", error); goto leave; } /* Set channel name as "channel #" */ sprintf(buffer, "channel %d", (i + 1)); error = ts3server_setVariableAsString(vars, CHANNEL_NAME, buffer); if(error != ERROR_ok) { printf("Error setting channel %d name: %d", (i + 1), error); goto leave; } /* Make channel permanent */ error = ts3server_setVariableAsInt(vars, CHANNEL_FLAG_PERMANENT, 1); if(error != ERROR_ok) { printf("Error setting channel %d permanent: %d", (i + 1), error); goto leave; } } /* Finally create the virtual server, using the server parameters we setup earlier. * In addition automatically create all channels we set in the channel parameters, which is * included as part of the server parameters. * The function writes the virtual server ID into serverID variable */ error = ts3server_createVirtualServer2(vscp, VIRTUALSERVER_CREATE_FLAG_NONE, &serverID); if(error != ERROR_ok) { printf("Error during createVirtualServer2: %d\n", error); goto leave; } leave: /* Cleanup struct virtual server param. The included struct channel param will be automatically * freed when the virtual server param is freed, so you do not need to call freeMemory on * the channel params, too. */ ts3server_freeMemory(vscp); /* Finally return the virtual server ID of our just created virtual server */ return serverID; } uint64 startVirtualServer() { int n; int port; unsigned int maxClients; char name[BUFSIZ]; /* Ask user for server port */ printf("\nEnter server port (default 9987): "); n = scanf("%d", &port); emptyInputBuffer(); if(n == 0) { printf("Invalid input. Please enter a number.\n\n"); return 0; } printf("\nEnter server capacity (default %d): ", MAX_CLIENTS); n = scanf("%d", &maxClients); emptyInputBuffer(); if(n == 0) { printf("Invalid input. Please enter a number.\n\n"); return 0; } /* Ask user for server name */ enterName(name); return createVirtualServer2(name, port, maxClients); } void editVirtualServer() { int n; uint64 serverID; int currentSlotCount, newSlotCount; unsigned int error; printf("\nEnter ID of virtual server to edit: "); n = scanf("%llu", (unsigned long long*)&serverID); emptyInputBuffer(); if(n == 0) { printf("Invalid input. Please enter a number.\n\n"); return; } if((error = ts3server_getVirtualServerVariableAsInt(serverID, VIRTUALSERVER_MAXCLIENTS, ¤tSlotCount)) != ERROR_ok) { printf("Error getting the current capcity of virtual server: %d\n\n", error); return; } printf("\nEnter new capacity of virtual server (currently %d): ", currentSlotCount); n = scanf("%d", &newSlotCount); emptyInputBuffer(); if(n == 0) { printf("Invalid input. Please enter a number.\n\n"); return; } if((error = ts3server_setVirtualServerVariableAsInt(serverID, VIRTUALSERVER_MAXCLIENTS, newSlotCount)) != ERROR_ok) { printf("Error setting the new capacity: %d\n\n", error); return; } if((error = ts3server_flushVirtualServerVariable(serverID)) != ERROR_ok) { printf("Error flushing server variable updates %d\n\n", error); return; } } void stopVirtualServer() { int n; uint64 serverID; unsigned int error; printf("\nEnter ID of virtual server to stop: "); n = scanf("%llu", (unsigned long long*)&serverID); emptyInputBuffer(); if(n == 0) { printf("Invalid input. Please enter a number.\n\n"); return; } if((error = ts3server_stopVirtualServer(serverID)) != ERROR_ok) { printf("Error stopping virtual server: %d\n\n", error); } } int main(int argc, char **argv) { char *version; short abort = 0; uint64 serverID; unsigned int error; int unknownInput = 0; uint64* ids; int i; /* Create struct for callback function pointers */ struct ServerLibFunctions funcs; /* Initialize all callbacks with NULL */ memset(&funcs, 0, sizeof(struct ServerLibFunctions)); /* Now assign the used callback function pointers */ funcs.onClientConnected = onClientConnected; funcs.onClientDisconnected = onClientDisconnected; funcs.onClientMoved = onClientMoved; funcs.onChannelCreated = onChannelCreated; funcs.onChannelEdited = onChannelEdited; funcs.onChannelDeleted = onChannelDeleted; /* Initialize server lib with callbacks */ if((error = ts3server_initServerLib(&funcs, LogType_FILE | LogType_CONSOLE | LogType_USERLOGGING, NULL, argc, (const char* const *)argv)) != ERROR_ok) { char* errormsg; if(ts3server_getGlobalErrorMessage(error, &errormsg) == ERROR_ok) { printf("Error initialzing serverlib: %s\n", errormsg); ts3server_freeMemory(errormsg); } return 1; } printf("Server running\n"); /* Query and print server lib version */ if((error = ts3server_getServerLibVersion(&version)) != ERROR_ok) { printf("Error querying server lib version: %d\n", error); return 1; } printf("Server lib version: %s\n", version); ts3server_freeMemory(version); /* Release dynamically allocated memory */ /* Create a virtual server with the new server params method */ serverID = createVirtualServer2("TS3 SDK Test Server", 9987, MAX_CLIENTS); /* Simple commandline interface */ printf("\nTeamSpeak 3 server commandline interface\n"); showHelp(); while(!abort) { int c; if(unknownInput == 0) { printf("\nEnter Command (h for help)> "); } unknownInput = 0; c = getchar(); switch(c) { case 'q': printf("\nShutting down server...\n"); abort = 1; break; case 'h': showHelp(); break; case 'v': showVirtualServers(); break; case 'c': showChannels(serverID); break; case 'l': showClients(serverID); break; case 'n': { char name[BUFSIZ]; createDefaultChannelName(name); createChannel(serverID, name); break; } case 'N': { char name[BUFSIZ]; emptyInputBuffer(); enterName(name); createChannel(serverID, name); break; } case 'd': deleteChannel(serverID); break; case 'C': startVirtualServer(); break; case 'E': editVirtualServer(); break; case 'S': stopVirtualServer(); break; default: unknownInput = 1; } SLEEP(50); } /* Stop virtual servers to make sure connected clients are notified instead of dropped */ if((error = ts3server_getVirtualServerList(&ids)) != ERROR_ok) { /* Get array of virtual server IDs */ printf("Error getting virtual server list: %d\n", error); } else { for(i=0; ids[i]; i++) { if((error = ts3server_stopVirtualServer(ids[i])) != ERROR_ok) { printf("Error stopping virtual server: %d\n", error); break; } } ts3server_freeMemory(ids); } /* Shutdown server lib */ if((error = ts3server_destroyServerLib()) != ERROR_ok) { printf("Error destroying server lib: %d\n", error); return 1; } return 0; }