diff --git a/server/src/Group.cpp b/server/src/Group.cpp index 771b7f1..851baa8 100644 --- a/server/src/Group.cpp +++ b/server/src/Group.cpp @@ -618,41 +618,65 @@ bool GroupManager::isClientCached(const ClientDbId& client_database_id) { return this->resolve_cached_client(client_database_id) == nullptr; } +constexpr static auto kGroupMemberListQuery{R"( + SELECT + assignedGroups.cldbid, + clients_server.client_unique_id, + clients_server.client_nickname, + assignedGroups.channelId, + assignedGroups.until + FROM assignedGroups + INNER JOIN clients_server ON + clients_server.client_database_id = assignedGroups.cldbid AND clients_server.server_id = :sid + WHERE assignedGroups.`serverId` = :sid AND `groupId` = :gid; +)"}; + typedef std::vector> ResList; -std::vector> GroupManager::listGroupMembers(std::shared_ptr group, bool names) { //TODO juse inner join only on names = true +std::deque GroupManager::listGroupMembers(std::shared_ptr group, bool names) { if(!isLocalGroup(group)){ - if(this->root) return this->root->listGroupMembers(group, names); + if(this->root) + return this->root->listGroupMembers(group, names); return {}; } - ResList result; - sql::command(this->sql, - "SELECT assignedGroups.cldbid, assignedGroups.channelId, assignedGroups.until, clients.clientUid, clients.lastName FROM assignedGroups INNER JOIN clients ON (clients.cldbid = assignedGroups.cldbid AND clients.serverId = assignedGroups.serverId) WHERE assignedGroups.`serverId` = :sid AND `groupId` = :gid;", - variable{":sid", this->getServerId()}, variable{":gid", group->groupId()}) - .query([&](ResList* list, int columnCount, char** values, char** columnName){ - std::shared_ptr member = std::make_shared(); - member->displayName = "undefined"; - member->uid = "undefined"; - for(int index = 0; index < columnCount; index++){ - if(values[index] == nullptr) { - logError(this->getServerId(), string() + "Invalid value at " + columnName[index]); - continue; - } - if(strcmp(columnName[index], "cldbid") == 0) - member->cldbId = stoll(values[index]); - else if(strcmp(columnName[index], "until") == 0) - member->until = time_point() + milliseconds(stoll(values[index])); - else if(strcmp(columnName[index], "clientUid") == 0) - member->uid = values[index]; - else if(strcmp(columnName[index], "lastName") == 0) - member->displayName = values[index]; - else if(strcmp(columnName[index], "channelId") == 0) - member->channelId = stoll(values[index]); - else cerr << "Invalid column name " << columnName[index] << endl; + std::deque result{}; + + size_t set_index{0}; + sql::command{this->sql, std::string{kGroupMemberListQuery}, variable{":sid", this->getServerId()}, variable{":gid", group->groupId()}} + .query([&](int length, std::string* values, std::string* names) { + set_index++; + + auto index{0}; + try { + auto& member = result.emplace_back(); + assert(names[index] == "cldbid"); + member.cldbId = std::stoull(values[index++]); + + assert(names[index] == "client_unique_id"); + member.uid = values[index++]; + + assert(names[index] == "client_nickname"); + member.displayName = values[index++]; + + assert(names[index] == "channelId"); + member.channelId = std::stoull(values[index++]); + + assert(names[index] == "until"); + member.until = std::chrono::system_clock::time_point{} + std::chrono::milliseconds{std::stoll(values[index++])}; + + assert(index == length); + } catch (std::exception& ex) { + result.pop_back(); + logError(this->getServerId(), "Failed to parse client group assignment for group {}: {}. Set index: {}, Column: {}", + group->groupId(), + ex.what(), + set_index - 1, + index - 1 + ); + return; } - list->push_back(member); - return 0; - }, &result); + }); + return result; } diff --git a/server/src/Group.h b/server/src/Group.h index eab8861..cffbc08 100644 --- a/server/src/Group.h +++ b/server/src/Group.h @@ -198,7 +198,7 @@ namespace ts { bool renameGroup(std::shared_ptr, std::string); bool deleteGroup(std::shared_ptr); bool deleteAllGroups(); - std::vector> listGroupMembers(std::shared_ptr, bool names = false); + std::deque listGroupMembers(std::shared_ptr, bool names = false); std::vector> listGroupAssignments(ClientDbId client); void cleanupAssignments(ClientDbId); diff --git a/server/src/client/command_handler/server.cpp b/server/src/client/command_handler/server.cpp index bcff40a..ad567eb 100644 --- a/server/src/client/command_handler/server.cpp +++ b/server/src/client/command_handler/server.cpp @@ -578,11 +578,14 @@ command_result ConnectedClient::handleCommandServerGroupClientList(Command &cmd) notify["sgid"] = cmd["sgid"].as(); int index = 0; for (const auto &clientEntry : groupManager->listGroupMembers(serverGroup)) { - notify[index]["cldbid"] = clientEntry->cldbId; - notify[index]["client_nickname"] = clientEntry->displayName; - notify[index]["client_unique_identifier"] = clientEntry->uid; + notify[index]["cldbid"] = clientEntry.cldbId; + notify[index]["client_nickname"] = clientEntry.displayName; + notify[index]["client_unique_identifier"] = clientEntry.uid; index++; } + if(index == 0) + return ts::command_result{error::database_empty_result}; + this->sendCommand(notify); return command_result{error::ok}; } diff --git a/server/src/client/voice/CryptSetupHandler.cpp b/server/src/client/voice/CryptSetupHandler.cpp index 32f6e96..925bcf5 100644 --- a/server/src/client/voice/CryptSetupHandler.cpp +++ b/server/src/client/voice/CryptSetupHandler.cpp @@ -133,7 +133,7 @@ CryptSetupHandler::CommandResult CryptSetupHandler::handleCommandClientInitIv(co std::string clientOmega = base64::decode(cmd.value("omega")); //The identity public key std::string ip = cmd.value("ip"); - bool ot = cmd.has_key("ot") ? cmd.value_as("ot") : false; + bool ot = cmd.has_key("ot") && cmd.value_as("ot"); { this->remote_key = std::shared_ptr(new ecc_key{}, [](ecc_key* key){ diff --git a/server/src/manager/BanManager.cpp b/server/src/manager/BanManager.cpp index 25fb22a..f6def31 100644 --- a/server/src/manager/BanManager.cpp +++ b/server/src/manager/BanManager.cpp @@ -179,7 +179,7 @@ std::shared_ptr BanManager::findBanExact(ts::ServerId server_id, cons } std::deque> BanManager::listBans(ServerId sid) { - auto command = sql::command(this->sql, "SELECT `bannedClients`.*, clients.`clientUid` AS `invUid`, clients.`lastName` AS `invName` FROM `bannedClients` INNER JOIN clients ON clients.cldbid = bannedClients.invokerDbId AND clients.serverId = bannedClients.serverId WHERE bannedClients.`serverId` = :sid" UNTIL_SQL, + auto command = sql::command(this->sql, "SELECT `bannedClients`.*, clients_server.`client_unique_id` AS `invUid`, clients_server.`client_nickname` AS `invName` FROM `bannedClients` INNER JOIN clients_server ON clients_server.client_database_id = bannedClients.invokerDbId AND clients_server.server_id = :sid WHERE bannedClients.`serverId` = :sid" UNTIL_SQL, variable{":time", duration_cast(system_clock::now().time_since_epoch()).count()}, variable{":sid", sid}); return resolveBansByQuery(command);