From 61691efacd76d7cc7b7054c76fe24dbec16dc1b4 Mon Sep 17 00:00:00 2001 From: Bkacjios Date: Thu, 27 May 2021 20:59:34 -0400 Subject: [PATCH] Changed mumble.client:sendPluginData() to use varargs rather than a table Updated stb_vorbis.c to latest Added mumble.user:listen(mumble.channel) Added mumble.user:unlisten(mumble.channel) Added mumble.user:getListens() Added mumble.voicetarget:getUsers() Added mumble.voicetarget:getGroup() Added mumble.voicetarget:getLinks() Added mumble.voicetarget:getChildren() --- README.md | 58 ++++++++++++++++---- banentry.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++ banentry.h | 6 +++ client.c | 41 +++++++------- mumble.c | 58 ++++++++++++++++++++ mumble.h | 3 ++ packet.c | 91 ++++++++----------------------- stb_vorbis.c | 20 ++++--- target.c | 37 +++++++++++++ user.c | 75 ++++++++++++++++++++++++++ 10 files changed, 433 insertions(+), 106 deletions(-) create mode 100644 banentry.c create mode 100644 banentry.h diff --git a/README.md b/README.md index 57cedbe..312216d 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ mumble.client:disconnect() -- Transmit a plugin data packet -- Users table can be a table of mumble.user's OR session numbers -mumble.client:sendPluginData(String dataID, String plugindata, Table users) +mumble.client:sendPluginData(String dataID, String plugindata, [mumble.user, Number session] ...) -- Transmit a raw, encoded, opus packet -- Set speaking to false at the end of a stream @@ -143,7 +143,8 @@ Table hooks = { ["OnServerPing"] = { ["hook"] = function: 0xffffffff, ["do stuff on ping"] = function: 0xffffffff, - } + }, + ... } -- Register a mumble.voicetarget to the server @@ -178,25 +179,21 @@ Table users = mumble.client:getUsers() Table users = { [session] = mumble.user, [session] = mumble.user, - [session] = mumble.user, - [session] = mumble.user, - [session] = mumble.user, + ... } +mumble.channel channel = mumble.client:getChannel(String path) + -- Returns a table of all mumble.channels Table channels = mumble.client:getChannels() -mumble.channel channel = mumble.client:getChannel(String path) - -- Structure -- Key: channel id -- Value: mumble.channel Table channels = { [id] = mumble.channel, [id] = mumble.channel, - [id] = mumble.channel, - [id] = mumble.channel, - [id] = mumble.channel, + ... } ``` @@ -287,6 +284,24 @@ String hash = mumble.user:getHash() -- Sets the users avatar image using a string of bytes mumble.user:setTexure(String bytes) + +-- Adds a channel to the list of channels the user is listening to +mumble.user:listen(mumble.channel ...) + +-- Removes a channel from the list of channels the user is listening to +mumble.user:unlisten(mumble.channel ...) + +-- Returns a table of all channels the user is currently listening to +Table listens = mumble.user:getListens() + +-- Structure +-- Key: channel id +-- Value: mumble.channel +Table channels = { + [id] = mumble.channel, + [id] = mumble.channel, + ... +} ``` ### mumble.channel @@ -400,6 +415,18 @@ mumble.timer:stop() -- Add a user to whisper to mumble.voicetarget:addUser(mumble.user user) +-- Return a table of all the users currently in the voicetarget +Table users = mumble.voicetarget:getUsers() + +-- Structure +-- Key: index +-- Value: Number session +Table channels = { + Number session, + Number session, + ... +} + -- Sets the channel that is be shouted to mumble.voicetarget:setChannel(mumble.channel channel) @@ -409,11 +436,20 @@ mumble.voicetarget:getChannel() -- Sets the specific user group to whisper to mumble.voicetarget:setGroup(String group) +-- Gets the group name we are whispering to +String group = mumble.voicetarget:getGroup() + -- Shout to the linked channels of the set channel mumble.voicetarget:setLinks(Boolean followlinks) +-- Returns if we are currently shouting to linked channels of the set channel +Boolean links = mumble.voicetarget:getLinks() + -- Shout to the children of the set channel mumble.voicetarget:setChildren(Boolean followchildren) + +-- Returns if we are currently shouting to children of the set channel +Boolean children = mumble.voicetarget:getChildren() ``` ### mumble.encoder @@ -937,7 +973,7 @@ ___ ### `OnPluginData (mumble.client client, Table event)` -Called when the servers suggest the client to use specific settings. +Called when the client receives plugin data from the server. ``` lua Table event = { diff --git a/banentry.c b/banentry.c new file mode 100644 index 0000000..5f6268e --- /dev/null +++ b/banentry.c @@ -0,0 +1,150 @@ +#include "mumble.h" + +#include "channel.h" +#include "user.h" +#include "banentry.h" + +int mumble_banentry_new(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = lua_newuserdata(l, sizeof(MumbleProto__BanList__BanEntry)); + mumble_proto__ban_list__ban_entry__init(entry); + + entry->address.data = (uint8_t *) luaL_checklstring(l, 1, &entry->address.len); + entry->mask = luaL_checkinteger(l, 2); + + luaL_getmetatable(l, METATABLE_BANENTRY); + lua_setmetatable(l, -2); + return 1; +} + +static int banentry_setAddress(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + entry->address.data = (uint8_t *) luaL_checklstring(l, 2, &entry->address.len); + return 0; +} + + +static int banentry_getAddress(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + mumble_push_address(l, entry->address); + return 1; +} + +static int banentry_setMask(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + entry->mask = luaL_checkinteger(l, 2); + return 0; +} + +static int banentry_getMask(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + lua_pushinteger(l, entry->mask); + return 1; +} + +static int banentry_setName(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + entry->name = (char*) luaL_checkstring(l, 2); + return 0; +} + + +static int banentry_getName(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + lua_pushstring(l, entry->name); + return 1; +} + +static int banentry_setHash(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + entry->hash = (char*) luaL_checkstring(l, 2); + return 0; +} + + +static int banentry_getHash(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + lua_pushstring(l, entry->hash); + return 1; +} + +static int banentry_setReason(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + entry->reason = (char*) luaL_checkstring(l, 2); + return 0; +} + + +static int banentry_getReason(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + lua_pushstring(l, entry->reason); + return 1; +} + +static int banentry_setStart(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + entry->start = (char*) luaL_checkstring(l, 2); + return 0; +} + + +static int banentry_getStart(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + lua_pushstring(l, entry->start); + return 1; +} + +static int banentry_setDuration(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + entry->duration = luaL_checkinteger(l, 2); + return 0; +} + + +static int banentry_getDuration(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + lua_pushinteger(l, entry->duration); + return 1; +} + +static int banentry_tostring(lua_State *l) +{ + MumbleProto__BanList__BanEntry *entry = luaL_checkudata(l, 1, METATABLE_BANENTRY); + + lua_pushfstring(l, "%s: %p", METATABLE_BANENTRY, entry); + return 1; +} + + +const luaL_Reg mumble_banentry[] = { + {"setAddress", banentry_setAddress}, + {"getAddress", banentry_setAddress}, + {"setMask", banentry_setMask}, + {"getMask", banentry_getMask}, + {"setName", banentry_setName}, + {"getName", banentry_getName}, + {"setHash", banentry_setHash}, + {"getHash", banentry_getHash}, + {"setReason", banentry_setReason}, + {"getReason", banentry_getReason}, + {"setStart", banentry_setStart}, + {"getStart", banentry_getStart}, + {"setDuration", banentry_setDuration}, + {"getDuration", banentry_getDuration}, + {"__tostring", banentry_tostring}, + {NULL, NULL} +}; \ No newline at end of file diff --git a/banentry.h b/banentry.h new file mode 100644 index 0000000..0937592 --- /dev/null +++ b/banentry.h @@ -0,0 +1,6 @@ +#pragma once + +#define METATABLE_BANENTRY "mumble.banentry" + +extern int mumble_banentry_new(lua_State *l); +extern const luaL_Reg mumble_banentry[]; \ No newline at end of file diff --git a/client.c b/client.c index 2428e49..ab32b10 100644 --- a/client.c +++ b/client.c @@ -5,6 +5,7 @@ #include "channel.h" #include "packet.h" #include "target.h" +#include "user.h" /*-------------------------------- MUMBLE CLIENT META METHODS @@ -156,34 +157,32 @@ static int client_sendPluginData(lua_State *l) data.has_data = true; data.data = cbdata; - luaL_checktype(l, 4, LUA_TTABLE); - lua_pushvalue(l, 4); - lua_pushnil(l); - - int i = 0; - int len = lua_objlen(l, 4); + int n_receiversessions = lua_gettop(l) - 3; - data.receiversessions = malloc(sizeof(uint32_t) * len); - data.n_receiversessions = len; + data.n_receiversessions = n_receiversessions; + data.receiversessions = malloc(sizeof(uint32_t) * n_receiversessions); - while (lua_next(l, -2)) { - lua_pushvalue(l, -2); - if (i < len) { - // Allow a table of users or session IDs - if (lua_isuserdata(l, -2)) { - MumbleUser *user = lua_touserdata(l, -2); - data.receiversessions[i++] = user->session; - } else if (lua_isnumber(l, -2)) { - uint32_t session = (uint32_t) lua_tonumber(l, -2); - data.receiversessions[i++] = session; + for (int i = 0; i < n_receiversessions; i++) { + int sp = 4+i; + switch (lua_type(l, sp)) { + case LUA_TNUMBER: + { + // Use direct session number + uint32_t session = (uint32_t) lua_tonumber(l, sp); + data.receiversessions[i] = session; + break; + } + case LUA_TTABLE: + { + // Make sure the "table" is a user metatable + MumbleUser *user = luaL_checkudata(l, sp, METATABLE_USER); + data.receiversessions[i] = user->session; + break; } } - lua_pop(l, 2); } - lua_pop(l, 1); packet_send(client, PACKET_PLUGINDATA, &data); - free(data.receiversessions); return 0; } diff --git a/mumble.c b/mumble.c index eaaa4c1..33d0e6a 100644 --- a/mumble.c +++ b/mumble.c @@ -2,6 +2,7 @@ #include "audio.h" #include "acl.h" +#include "banentry.h" #include "channel.h" #include "encoder.h" #include "decoder.h" @@ -640,6 +641,46 @@ void mumble_channel_remove(lua_State* l, MumbleClient* client, uint32_t channel_ lua_pop(l, 1); } +int mumble_push_address(lua_State* l, ProtobufCBinaryData address) +{ + lua_newtable(l); + uint8_t* bytes = (uint8_t*) address.data; + uint64_t* addr = (uint64_t*) address.data; + uint16_t* shorts = (uint16_t*) address.data; + + if (addr[0] != 0ULL || shorts[4] != 0 || shorts[5] != 0xFFFF) { + char ipv6[40]; + sprintf(ipv6,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + bytes[0], bytes[1], bytes[2], bytes[3], + bytes[4], bytes[5], bytes[5], bytes[7], + bytes[8], bytes[9], bytes[10], bytes[11], + bytes[12], bytes[13], bytes[14], bytes[15]); + + lua_pushboolean(l, true); + lua_setfield(l, -2, "ipv6"); + lua_pushstring(l, ipv6); + lua_setfield(l, -2, "string"); + } else { + char ipv4[16]; + sprintf(ipv4, "%d.%d.%d.%d", bytes[12], bytes[13], bytes[14], bytes[15]); + + lua_pushboolean(l, true); + lua_setfield(l, -2, "ipv4"); + lua_pushstring(l, ipv4); + lua_setfield(l, -2, "string"); + } + + lua_newtable(l); + for (uint32_t k = 0; k < address.len; k++) { + lua_pushinteger(l, k+1); + lua_pushinteger(l, address.data[k]); + lua_settable(l, -3); + } + lua_setfield(l, -2, "data"); + + return 1; +} + const luaL_Reg mumble[] = { {"connect", mumble_connect}, {"loop", mumble_loop}, @@ -785,6 +826,23 @@ int luaopen_mumble(lua_State *l) lua_setmetatable(l, -2); lua_setfield(l, -2, "decoder"); + // Register voice target metatable + luaL_newmetatable(l, METATABLE_BANENTRY); + { + lua_pushvalue(l, -1); + lua_setfield(l, -2, "__index"); + } + luaL_register(l, NULL, mumble_banentry); + + // If you call the voice target metatable as a function it will return a new voice target object + lua_newtable(l); + { + lua_pushcfunction(l, mumble_banentry_new); + lua_setfield(l, -2, "__call"); + } + lua_setmetatable(l, -2); + lua_setfield(l, -2, "banentry"); + // Register voice target metatable luaL_newmetatable(l, METATABLE_VOICETARGET); { diff --git a/mumble.h b/mumble.h index b84c572..9c9acc9 100644 --- a/mumble.h +++ b/mumble.h @@ -205,6 +205,7 @@ struct MumbleUser char* texture_hash; size_t texture_hash_len; char* hash; + LinkNode* listens; }; typedef struct { @@ -259,5 +260,7 @@ extern MumbleChannel* mumble_channel_get(lua_State* l, MumbleClient* client, uin extern MumbleChannel* mumble_channel_raw_get(lua_State* l, MumbleClient* client, uint32_t channel_id); extern void mumble_channel_remove(lua_State* l, MumbleClient* client, uint32_t channel_id); +extern int mumble_push_address(lua_State* l, ProtobufCBinaryData address); + extern int mumble_traceback(lua_State *l); extern void mumble_hook_call(lua_State* l, MumbleClient *client, const char* hook, int nargs); \ No newline at end of file diff --git a/packet.c b/packet.c index 1fa150f..071b141 100644 --- a/packet.c +++ b/packet.c @@ -624,6 +624,27 @@ void packet_user_state(lua_State *l, MumbleClient *client, Packet *packet) lua_setfield(l, -2, "texture_hash"); free(result); } + if (state->n_listening_channel_add > 0) { + // Add the new entries to the head of the list + lua_newtable(l); + for (uint32_t i = 0; i < state->n_listening_channel_add; i++) { + list_add(&user->listens, state->listening_channel_add[i]); + lua_pushinteger(l, i+1); + mumble_channel_raw_get(l, client, state->listening_channel_add[i]); + lua_settable(l, -3); + } + lua_setfield(l , -2, "listening_channel_add"); + } + if (state->n_listening_channel_remove > 0) { + lua_newtable(l); + for (uint32_t i = 0; i < state->n_listening_channel_remove; i++) { + list_remove(&user->listens, state->listening_channel_remove[i]); + lua_pushinteger(l, i+1); + mumble_channel_raw_get(l, client, state->listening_channel_remove[i]); + lua_settable(l, -3); + } + lua_setfield(l , -2, "listening_channel_remove"); + } mumble_user_raw_get(l, client, state->session); lua_setfield(l, -2, "user"); @@ -651,40 +672,7 @@ void packet_ban_list(lua_State *l, MumbleClient *client, Packet *packet) MumbleProto__BanList__BanEntry *ban = list->bans[i]; lua_pushinteger(l, i+1); lua_newtable(l); - lua_newtable(l); - uint8_t* bytes = (uint8_t*) ban->address.data; - uint64_t* addr = (uint64_t*) ban->address.data; - uint16_t* shorts = (uint16_t*) ban->address.data; - - if (addr[0] != 0ULL || shorts[4] != 0 || shorts[5] != 0xFFFF) { - char ipv6[40]; - sprintf(ipv6,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", - bytes[0], bytes[1], bytes[2], bytes[3], - bytes[4], bytes[5], bytes[5], bytes[7], - bytes[8], bytes[9], bytes[10], bytes[11], - bytes[12], bytes[13], bytes[14], bytes[15]); - - lua_pushboolean(l, true); - lua_setfield(l, -2, "ipv6"); - lua_pushstring(l, ipv6); - lua_setfield(l, -2, "string"); - } else { - char ipv4[16]; - sprintf(ipv4, "%d.%d.%d.%d", bytes[12], bytes[13], bytes[14], bytes[15]); - - lua_pushboolean(l, true); - lua_setfield(l, -2, "ipv4"); - lua_pushstring(l, ipv4); - lua_setfield(l, -2, "string"); - } - - lua_newtable(l); - for (uint32_t k = 0; k < ban->address.len; k++) { - lua_pushinteger(l, k+1); - lua_pushinteger(l, ban->address.data[k]); - lua_settable(l, -3); - } - lua_setfield(l, -2, "data"); + mumble_push_address(l, ban->address); lua_setfield(l, -2, "address"); lua_pushinteger(l, ban->mask); @@ -1124,40 +1112,7 @@ void packet_user_stats(lua_State *l, MumbleClient *client, Packet *packet) lua_setfield(l, -2, "celt_versions"); if (stats->has_address) { - lua_newtable(l); - uint8_t* bytes = (uint8_t*) stats->address.data; - uint64_t* addr = (uint64_t*) stats->address.data; - uint16_t* shorts = (uint16_t*) stats->address.data; - - if (addr[0] != 0ULL || shorts[4] != 0 || shorts[5] != 0xFFFF) { - char ipv6[40]; - sprintf(ipv6,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", - bytes[0], bytes[1], bytes[2], bytes[3], - bytes[4], bytes[5], bytes[5], bytes[7], - bytes[8], bytes[9], bytes[10], bytes[11], - bytes[12], bytes[13], bytes[14], bytes[15]); - - lua_pushboolean(l, true); - lua_setfield(l, -2, "ipv6"); - lua_pushstring(l, ipv6); - lua_setfield(l, -2, "string"); - } else { - char ipv4[16]; - sprintf(ipv4, "%d.%d.%d.%d", bytes[12], bytes[13], bytes[14], bytes[15]); - - lua_pushboolean(l, true); - lua_setfield(l, -2, "ipv4"); - lua_pushstring(l, ipv4); - lua_setfield(l, -2, "string"); - } - - lua_newtable(l); - for (uint32_t k = 0; k < stats->address.len; k++) { - lua_pushinteger(l, k+1); - lua_pushinteger(l, stats->address.data[k]); - lua_settable(l, -3); - } - lua_setfield(l, -2, "data"); + mumble_push_address(l, stats->address); lua_setfield(l, -2, "address"); } diff --git a/stb_vorbis.c b/stb_vorbis.c index b28944a..a8cbfa6 100644 --- a/stb_vorbis.c +++ b/stb_vorbis.c @@ -1,4 +1,4 @@ -// Ogg Vorbis audio decoder - v1.19 - public domain +// Ogg Vorbis audio decoder - v1.20 - public domain // http://nothings.org/stb_vorbis/ // // Original version written by Sean Barrett in 2007. @@ -31,9 +31,11 @@ // Phillip Bennefall Rohit Thiago Goulart // github:manxorist saga musix github:infatum // Timur Gagiev Maxwell Koo Peter Waller -// github:audinowho Dougall Johnson +// github:audinowho Dougall Johnson David Reid +// github:Clownacy Pedro J. Estebanez Remi Verschelde // // Partial history: +// 1.20 - 2020-07-11 - several small fixes // 1.19 - 2020-02-05 - warnings // 1.18 - 2020-02-02 - fix seek bugs; parse header comments; misc warnings etc. // 1.17 - 2019-07-08 - fix CVE-2019-13217..CVE-2019-13223 (by ForAllSecure) @@ -577,7 +579,7 @@ enum STBVorbisError #if defined(_MSC_VER) || defined(__MINGW32__) #include #endif - #if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__) + #if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__) || defined(__NEWLIB__) #include #endif #else // STB_VORBIS_NO_CRT @@ -599,7 +601,9 @@ enum STBVorbisError #undef __forceinline #endif #define __forceinline + #ifndef alloca #define alloca __builtin_alloca + #endif #elif !defined(_MSC_VER) #if __GNUC__ #define __forceinline inline @@ -961,7 +965,7 @@ static void *setup_temp_malloc(vorb *f, int sz) static void setup_temp_free(vorb *f, void *p, int sz) { if (f->alloc.alloc_buffer) { - f->temp_offset += (sz+3)&~3; + f->temp_offset += (sz+7)&~7; return; } free(p); @@ -1600,7 +1604,8 @@ static uint32 get_bits(vorb *f, int n) f->valid_bits += 8; } } - if (f->valid_bits < 0) return 0; + + assert(f->valid_bits >= n); z = f->acc & ((1 << n)-1); f->acc >>= n; f->valid_bits -= n; @@ -3630,6 +3635,7 @@ static int start_decoder(vorb *f) //file vendor len = get32_packet(f); f->vendor = (char*)setup_malloc(f, sizeof(char) * (len+1)); + if (f->vendor == NULL) return error(f, VORBIS_outofmem); for(i=0; i < len; ++i) { f->vendor[i] = get8_packet(f); } @@ -3637,10 +3643,12 @@ static int start_decoder(vorb *f) //user comments f->comment_list_length = get32_packet(f); f->comment_list = (char**)setup_malloc(f, sizeof(char*) * (f->comment_list_length)); + if (f->comment_list == NULL) return error(f, VORBIS_outofmem); for(i=0; i < f->comment_list_length; ++i) { len = get32_packet(f); f->comment_list[i] = (char*)setup_malloc(f, sizeof(char) * (len+1)); + if (f->comment_list[i] == NULL) return error(f, VORBIS_outofmem); for(j=0; j < len; ++j) { f->comment_list[i][j] = get8_packet(f); @@ -4253,7 +4261,7 @@ static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z) memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start if (z) { p->alloc = *z; - p->alloc.alloc_buffer_length_in_bytes = (p->alloc.alloc_buffer_length_in_bytes+3) & ~3; + p->alloc.alloc_buffer_length_in_bytes &= ~7; p->temp_offset = p->alloc.alloc_buffer_length_in_bytes; } p->eof = 0; diff --git a/target.c b/target.c index 28a5c2c..17d2056 100644 --- a/target.c +++ b/target.c @@ -29,6 +29,18 @@ static int target_addUser(lua_State *l) return 0; } +static int target_getUsers(lua_State *l) +{ + MumbleProto__VoiceTarget__Target *target = luaL_checkudata(l, 1, METATABLE_VOICETARGET); + lua_newtable(l); + for (uint32_t i = 0; i < target->n_session; i++) { + lua_pushinteger(l, i+1); + lua_pushinteger(l, target->session[i]); + lua_settable(l, -2); + } + return 1; +} + static int target_setChannel(lua_State *l) { MumbleProto__VoiceTarget__Target *target = luaL_checkudata(l, 1, METATABLE_VOICETARGET); @@ -54,6 +66,13 @@ static int target_setGroup(lua_State *l) return 0; } +static int target_getGroup(lua_State *l) +{ + MumbleProto__VoiceTarget__Target *target = luaL_checkudata(l, 1, METATABLE_VOICETARGET); + lua_pushstring(l, target->group); + return 1; +} + static int target_setLinks(lua_State *l) { MumbleProto__VoiceTarget__Target *target = luaL_checkudata(l, 1, METATABLE_VOICETARGET); @@ -63,6 +82,13 @@ static int target_setLinks(lua_State *l) return 0; } +static int target_getLinks(lua_State *l) +{ + MumbleProto__VoiceTarget__Target *target = luaL_checkudata(l, 1, METATABLE_VOICETARGET); + lua_pushboolean(l, target->links); + return 1; +} + static int target_setChildren(lua_State *l) { MumbleProto__VoiceTarget__Target *target = luaL_checkudata(l, 1, METATABLE_VOICETARGET); @@ -72,6 +98,13 @@ static int target_setChildren(lua_State *l) return 0; } +static int target_getChildren(lua_State *l) +{ + MumbleProto__VoiceTarget__Target *target = luaL_checkudata(l, 1, METATABLE_VOICETARGET); + lua_pushboolean(l, target->children); + return 1; +} + static int target_tostring(lua_State *l) { MumbleProto__VoiceTarget__Target *target = luaL_checkudata(l, 1, METATABLE_VOICETARGET); @@ -89,11 +122,15 @@ static int target_gc(lua_State *l) const luaL_Reg mumble_target[] = { {"addUser", target_addUser}, + {"getUsers", target_getUsers}, {"setChannel", target_setChannel}, {"getChannel", target_getChannel}, {"setGroup", target_setGroup}, + {"getGroup", target_getGroup}, {"setLinks", target_setLinks}, + {"getLinks", target_getLinks}, {"setChildren", target_setChildren}, + {"getChildren", target_getChildren}, {"__tostring", target_tostring}, {"__gc", target_gc}, {NULL, NULL} diff --git a/user.c b/user.c index 42a420f..f36c4ba 100644 --- a/user.c +++ b/user.c @@ -297,6 +297,78 @@ static int user_tostring(lua_State *l) return 1; } +static int user_listen(lua_State *l) +{ + MumbleUser *user = luaL_checkudata(l, 1, METATABLE_USER); + + MumbleProto__UserState msg = MUMBLE_PROTO__USER_STATE__INIT; + + msg.has_session = true; + msg.session = user->session; + + // Get the number of channels we want to listen to + int n_listening_channel_add = lua_gettop(l) - 1; + + msg.n_listening_channel_add = n_listening_channel_add; + + msg.listening_channel_add = malloc(sizeof(uint32_t) * n_listening_channel_add); + + // Loop through each argument and add the channel_id to the array + for (int i = 0; i < n_listening_channel_add; i++) { + MumbleChannel *listen = luaL_checkudata(l, i+2, METATABLE_CHAN); + msg.listening_channel_add[i] = listen->channel_id; + } + + packet_send(user->client, PACKET_USERSTATE, &msg); + free(msg.listening_channel_add); + return 0; +} + +static int user_unlisten(lua_State *l) +{ + MumbleUser *user = luaL_checkudata(l, 1, METATABLE_USER); + + MumbleProto__UserState msg = MUMBLE_PROTO__USER_STATE__INIT; + + msg.has_session = true; + msg.session = user->session; + + // Get the number of channels we want to unlink + int n_listening_channel_remove = lua_gettop(l) - 1; + + msg.n_listening_channel_remove = n_listening_channel_remove; + msg.listening_channel_remove = malloc(sizeof(uint32_t) * n_listening_channel_remove); + + for (int i = 0; i < n_listening_channel_remove; i++) { + MumbleChannel *listen = luaL_checkudata(l, i+2, METATABLE_CHAN); + msg.listening_channel_remove[i] = listen->channel_id; + } + + packet_send(user->client, PACKET_USERSTATE, &msg); + free(msg.listening_channel_remove); + return 0; +} + +static int user_getListens(lua_State *l) +{ + MumbleUser *user = luaL_checkudata(l, 1, METATABLE_USER); + + lua_newtable(l); + + LinkNode * current = user->listens; + + // Add all linked channels to the table + while (current != NULL) { + lua_pushinteger(l, current->data); + mumble_channel_raw_get(l, user->client, current->data); + lua_settable(l, -3); + + current = current->next; + } + + return 1; +} + static int user_gc(lua_State *l) { MumbleUser *user = luaL_checkudata(l, 1, METATABLE_USER); @@ -364,6 +436,9 @@ const luaL_Reg mumble_user[] = { {"getTextureHash", user_getTextureHash}, {"getHash", user_getHash}, {"setTexture", user_setTexture}, + {"listen", user_listen}, + {"unlisten", user_unlisten}, + {"getListens", user_getListens}, {"__gc", user_gc}, {"__tostring", user_tostring},