Teaspeak-Server/server/src/client/ConnectedClientNotifyHandler.cpp

823 lines
34 KiB
C++
Raw Normal View History

#include <iostream>
#include <bitset>
#include <algorithm>
#include "ConnectedClient.h"
#include "voice/VoiceClient.h"
#include "../server/file/FileServer.h"
#include "../server/VoiceServer.h"
#include "../InstanceHandler.h"
#include "../server/QueryServer.h"
2019-08-25 23:55:55 +02:00
#include "../manager/PermissionNameMapper.h"
#include "music/MusicClient.h"
#include <log/LogUtils.h>
#include <misc/sassert.h>
#include <misc/timer.h>
2019-08-25 22:16:42 +02:00
#include "./web/WebClient.h"
using namespace std::chrono;
using namespace std;
using namespace ts;
using namespace ts::server;
using namespace ts::token;
extern ts::server::InstanceHandler* serverInstance;
#define INVOKER(command, invoker) \
do { \
if(invoker) { \
2020-01-24 02:57:58 +01:00
command["invokerid"] = invoker->getClientId(); \
command["invokername"] = invoker->getDisplayName(); \
command["invokeruid"] = invoker->getUid(); \
} else { \
2020-01-24 02:57:58 +01:00
command["invokerid"] = 0; \
command["invokername"] = "undefined"; \
command["invokeruid"] = "undefined"; \
} \
} while(0)
bool ConnectedClient::notifyServerGroupList() {
2020-01-24 02:57:58 +01:00
Command cmd(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifyservergrouplist" : "");
int index = 0;
2020-01-24 02:57:58 +01:00
for (const auto& group : (this->server ? this->server->groups : serverInstance->getGroupManager().get())->availableServerGroups(true)) {
if(group->target() == GroupTarget::GROUPTARGET_CHANNEL) {
cmd[index]["cgid"] = group->groupId();
} else {
cmd[index]["sgid"] = group->groupId();
}
for (const auto &prop : group->properties().list_properties(property::FLAG_GROUP_VIEW, this->getType() == CLIENT_TEAMSPEAK ? property::FLAG_NEW : (uint16_t) 0))
cmd[index][prop.type().name] = prop.value();
2020-01-24 02:57:58 +01:00
auto modify_power = group->permissions()->permission_value_flagged(permission::i_displayed_group_needed_modify_power);
auto add_power = group->permissions()->permission_value_flagged(permission::i_displayed_group_needed_member_add_power);
auto remove_power = group->permissions()->permission_value_flagged(permission::i_displayed_group_needed_member_remove_power);
cmd[index]["n_modifyp"] = modify_power.has_value ? modify_power.value : 0;
cmd[index]["n_member_addp"] = add_power.has_value ? add_power.value : 0;
cmd[index]["n_member_removep"] = remove_power.has_value ? remove_power.value : 0;
index++;
}
2020-01-24 02:57:58 +01:00
this->sendCommand(cmd);
return true;
}
2019-07-23 15:53:20 +02:00
bool ConnectedClient::notifyGroupPermList(const std::shared_ptr<Group>& group, bool as_sid) {
2020-01-24 02:57:58 +01:00
Command cmd(this->getExternalType() == CLIENT_TEAMSPEAK ? group->target() == GROUPTARGET_SERVER ? "notifyservergrouppermlist" : "notifychannelgrouppermlist" : "");
if (group->target() == GROUPTARGET_SERVER)
cmd["sgid"] = group->groupId();
else
cmd["cgid"] = group->groupId();
int index = 0;
auto permissions = group->permissions()->permissions();
auto permission_mapper = serverInstance->getPermissionMapper();
auto client_type = this->getType();
for (const auto &permission_data : permissions) {
auto& permission = get<1>(permission_data);
if(!permission.flags.value_set)
continue;
if(as_sid) {
cmd[index]["permsid"] = permission_mapper->permission_name(client_type, get<0>(permission_data));
} else {
cmd[index]["permid"] = (uint16_t) get<0>(permission_data);
}
cmd[index]["permvalue"] = permission.values.value;
cmd[index]["permnegated"] = permission.flags.negate;
cmd[index]["permskip"] = permission.flags.skip;
index++;
}
for (const auto &permission_data : permissions) {
auto& permission = get<1>(permission_data);
if(!permission.flags.grant_set)
continue;
if(as_sid) {
cmd[index]["permsid"] = permission_mapper->permission_name_grant(client_type, get<0>(permission_data));
} else {
cmd[index]["permid"] = (uint16_t) (get<0>(permission_data) | PERM_ID_GRANT);
}
cmd[index]["permvalue"] = permission.values.grant;
cmd[index]["permnegated"] = permission.flags.negate;
cmd[index]["permskip"] = permission.flags.skip;
index++;
}
if (index == 0)
return false;
this->sendCommand(cmd);
return true;
}
bool ConnectedClient::notifyClientPermList(ClientDbId cldbid, const std::shared_ptr<permission::v2::PermissionManager>& mgr, bool perm_sids) {
2020-01-24 02:57:58 +01:00
Command res(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifyclientpermlist" : "");
auto permissions = mgr->permissions();
if(permissions.empty())
return false;
int index = 0;
res[index]["cldbid"] = cldbid;
auto permission_mapper = serverInstance->getPermissionMapper();
auto client_type = this->getType();
for (const auto &permission_data : permissions) {
auto& permission = std::get<1>(permission_data);
if(permission.flags.value_set) {
if (perm_sids)
res[index]["permsid"] = permission_mapper->permission_name(client_type, get<0>(permission_data));
else
res[index]["permid"] = get<0>(permission_data);
res[index]["permvalue"] = permission.values.value;
res[index]["permnegated"] = permission.flags.negate;
res[index]["permskip"] = permission.flags.skip;
index++;
}
if(permission.flags.grant_set) {
if (perm_sids)
res[index]["permsid"] = permission_mapper->permission_name_grant(client_type, get<0>(permission_data));
else
res[index]["permid"] = (get<0>(permission_data) | PERM_ID_GRANT);
res[index]["permvalue"] = permission.values.grant;
res[index]["permnegated"] = 0;
res[index]["permskip"] = 0;
index++;
}
}
this->sendCommand(res);
return true;
}
bool ConnectedClient::notifyChannelGroupList() {
2020-01-24 02:57:58 +01:00
Command cmd(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifychannelgrouplist" : "");
int index = 0;
for (const auto &group : (this->server ? this->server->groups : serverInstance->getGroupManager().get())->availableChannelGroups(true)) {
if(group->target() == GroupTarget::GROUPTARGET_CHANNEL) {
cmd[index]["cgid"] = group->groupId();
} else {
cmd[index]["sgid"] = group->groupId();
}
for (auto &prop : group->properties().list_properties(property::FLAG_GROUP_VIEW, this->getType() == CLIENT_TEAMSPEAK ? property::FLAG_NEW : (uint16_t) 0))
cmd[index][prop.type().name] = prop.value();
auto modify_power = group->permissions()->permission_value_flagged(permission::i_displayed_group_needed_modify_power);
auto add_power = group->permissions()->permission_value_flagged(permission::i_displayed_group_needed_member_add_power);
auto remove_power = group->permissions()->permission_value_flagged(permission::i_displayed_group_needed_member_remove_power);
cmd[index]["n_modifyp"] = modify_power.has_value ? modify_power.value : 0;
cmd[index]["n_member_addp"] = add_power.has_value ? add_power.value : 0;
cmd[index]["n_member_removep"] = remove_power.has_value ? remove_power.value : 0;
index++;
}
if(index == 0) return false;
this->sendCommand(cmd);
return true;
}
2019-08-20 13:46:23 +02:00
bool ConnectedClient::notifyTextMessage(ChatMessageMode mode, const shared_ptr<ConnectedClient> &invoker, uint64_t targetId, ChannelId channel_id, const std::chrono::system_clock::time_point& timestamp, const string &textMessage) {
2020-01-24 02:57:58 +01:00
//notifytextmessage targetmode=1 msg=asdasd target=2 invokerid=1 invokername=WolverinDEV invokeruid=xxjnc14LmvTk+Lyrm8OOeo4tOqw=
Command cmd("notifytextmessage");
INVOKER(cmd, invoker);
cmd["targetmode"] = mode;
cmd["target"] = targetId;
cmd["msg"] = textMessage;
cmd["timestamp"] = floor<milliseconds>(timestamp.time_since_epoch()).count();
if(this->getType() != ClientType::CLIENT_TEAMSPEAK)
cmd["cid"] = channel_id;
this->sendCommand(cmd);
return true;
}
bool ConnectedClient::notifyServerGroupClientAdd(const shared_ptr<ConnectedClient> &invoker, const shared_ptr<ConnectedClient> &client, const shared_ptr<Group> &group) {
2020-01-24 02:57:58 +01:00
Command cmd("notifyservergroupclientadded");
INVOKER(cmd, invoker);
2020-01-24 02:57:58 +01:00
cmd["sgid"] = group->groupId();
cmd["clid"] = client->getClientId();
cmd["name"] = client->getDisplayName();
cmd["cluid"] = client->getUid();
2020-01-24 02:57:58 +01:00
this->sendCommand(cmd);
return true;
}
bool ConnectedClient::notifyServerGroupClientRemove(std::shared_ptr<ConnectedClient> invoker, std::shared_ptr<ConnectedClient> client, std::shared_ptr<Group> group) {
2020-01-24 02:57:58 +01:00
Command cmd("notifyservergroupclientdeleted");
INVOKER(cmd, invoker);
2020-01-24 02:57:58 +01:00
cmd["sgid"] = group->groupId();
cmd["clid"] = client->getClientId();
cmd["name"] = client->getDisplayName();
cmd["cluid"] = client->getUid();
2020-01-24 02:57:58 +01:00
this->sendCommand(cmd);
return true;
}
bool ConnectedClient::notifyClientChannelGroupChanged(
2020-01-24 02:57:58 +01:00
const std::shared_ptr<ConnectedClient> &invoker,
const std::shared_ptr<ConnectedClient> &client,
const std::shared_ptr<BasicChannel>& channel,
const std::shared_ptr<BasicChannel>& inherited,
const std::shared_ptr<Group>& group,
bool lock_channel_tree) {
assert(!lock_channel_tree); /* not supported */
if(!this->isClientVisible(client, false) && client != this) return false;
if(client->getChannel() != channel) return false;
assert(client);
assert(channel);
assert(inherited);
assert(group);
Command cmd("notifyclientchannelgroupchanged");
INVOKER(cmd, invoker);
2020-01-24 02:57:58 +01:00
cmd["cgid"] = group->groupId();
cmd["clid"] = client->getClientId();
cmd["cid"] = channel->channelId();
cmd["cgi"] = inherited ? inherited->channelId() : channel->channelId(); //The inherited channel
2020-01-24 02:57:58 +01:00
this->sendCommand(cmd);
return true;
}
2019-08-25 22:16:42 +02:00
bool ConnectedClient::notifyConnectionInfo(const shared_ptr<ConnectedClient> &target, const shared_ptr<ConnectionInfoData> &info) {
Command notify("notifyconnectioninfo");
notify["clid"] = target->getClientId();
2020-01-24 02:57:58 +01:00
auto not_set = this->getType() == CLIENT_TEAMSPEAK ? 0 : -1;
2019-09-14 12:06:48 +02:00
/* we deliver data to the web client as well, because its a bit dump :D */
2019-08-25 22:16:42 +02:00
if(target->getClientId() != this->getClientId()) {
2020-01-24 02:57:58 +01:00
auto report = target->connectionStatistics->full_report();
/* default values which normally sets the client */
notify["connection_bandwidth_received_last_minute_control"] = not_set;
notify["connection_bandwidth_received_last_minute_keepalive"] = not_set;
notify["connection_bandwidth_received_last_minute_speech"] = not_set;
notify["connection_bandwidth_received_last_second_control"] = not_set;
notify["connection_bandwidth_received_last_second_keepalive"] = not_set;
notify["connection_bandwidth_received_last_second_speech"] = not_set;
notify["connection_bandwidth_sent_last_minute_control"] = not_set;
notify["connection_bandwidth_sent_last_minute_keepalive"] = not_set;
notify["connection_bandwidth_sent_last_minute_speech"] = not_set;
notify["connection_bandwidth_sent_last_second_control"] = not_set;
notify["connection_bandwidth_sent_last_second_keepalive"] = not_set;
notify["connection_bandwidth_sent_last_second_speech"] = not_set;
/* its flipped here because the report is out of the clients view */
notify["connection_bytes_received_control"] = not_set;
notify["connection_bytes_received_keepalive"] = not_set;
notify["connection_bytes_received_speech"] = not_set;
notify["connection_bytes_sent_control"] = not_set;
notify["connection_bytes_sent_keepalive"] = not_set;
notify["connection_bytes_sent_speech"] = not_set;
/* its flipped here because the report is out of the clients view */
notify["connection_packets_received_control"] = not_set;
notify["connection_packets_received_keepalive"] = not_set;
notify["connection_packets_received_speech"] = not_set;
notify["connection_packets_sent_control"] = not_set;
notify["connection_packets_sent_keepalive"] = not_set;
notify["connection_packets_sent_speech"] = not_set;
notify["connection_server2client_packetloss_control"] = not_set;
notify["connection_server2client_packetloss_keepalive"] = not_set;
notify["connection_server2client_packetloss_speech"] = not_set;
notify["connection_server2client_packetloss_total"] = not_set;
notify["connection_ping"] = 0;
notify["connection_ping_deviation"] = 0;
notify["connection_connected_time"] = 0;
notify["connection_idle_time"] = 0;
/* its flipped here because the report is out of the clients view */
notify["connection_filetransfer_bandwidth_sent"] = report.file_bytes_received;
notify["connection_filetransfer_bandwidth_received"] = report.file_bytes_sent;
}
2020-01-24 02:57:58 +01:00
if(info) {
for(const auto& elm : info->properties) {
notify[elm.first] = elm.second;
}
} else {
//Fill in some server stuff
if(dynamic_pointer_cast<VoiceClient>(target))
notify["connection_ping"] = floor<milliseconds>(dynamic_pointer_cast<VoiceClient>(target)->calculatePing()).count();
else if(dynamic_pointer_cast<WebClient>(target))
notify["connection_ping"] = floor<milliseconds>(dynamic_pointer_cast<WebClient>(target)->client_ping()).count();
if(target->getType() == ClientType::CLIENT_TEASPEAK || target->getType() == ClientType::CLIENT_TEAMSPEAK || target->getType() == ClientType::CLIENT_WEB) {
auto report = target->connectionStatistics->full_report();
/* its flipped here because the report is out of the clients view */
notify["connection_bytes_received_control"] = report.connection_bytes_sent[stats::ConnectionStatistics::category::COMMAND];
notify["connection_bytes_received_keepalive"] = report.connection_bytes_sent[stats::ConnectionStatistics::category::ACK];
notify["connection_bytes_received_speech"] = report.connection_bytes_sent[stats::ConnectionStatistics::category::VOICE];
notify["connection_bytes_sent_control"] = report.connection_bytes_sent[stats::ConnectionStatistics::category::COMMAND];
notify["connection_bytes_sent_keepalive"] = report.connection_bytes_sent[stats::ConnectionStatistics::category::ACK];
notify["connection_bytes_sent_speech"] = report.connection_bytes_sent[stats::ConnectionStatistics::category::VOICE];
/* its flipped here because the report is out of the clients view */
notify["connection_packets_received_control"] = report.connection_packets_sent[stats::ConnectionStatistics::category::COMMAND];
notify["connection_packets_received_keepalive"] = report.connection_packets_sent[stats::ConnectionStatistics::category::ACK];
notify["connection_packets_received_speech"] = report.connection_packets_sent[stats::ConnectionStatistics::category::VOICE];
notify["connection_packets_sent_control"] = report.connection_packets_sent[stats::ConnectionStatistics::category::COMMAND];
notify["connection_packets_sent_keepalive"] = report.connection_packets_sent[stats::ConnectionStatistics::category::ACK];
notify["connection_packets_sent_speech"] = report.connection_packets_sent[stats::ConnectionStatistics::category::VOICE];
}
}
2019-09-14 12:06:48 +02:00
if(target->getClientId() == this->getClientId() || this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_remoteaddress_view, 1, target->currentChannel, true)) {
notify["connection_client_ip"] = target->getLoggingPeerIp();
notify["connection_client_port"] = target->getPeerPort();
}
2019-08-25 22:16:42 +02:00
//Needs to be filled out
2020-01-24 02:57:58 +01:00
notify["connection_client2server_packetloss_speech"] = not_set;
notify["connection_client2server_packetloss_keepalive"] = not_set;
notify["connection_client2server_packetloss_control"] = not_set;
notify["connection_client2server_packetloss_total"] = not_set;
2020-01-24 02:57:58 +01:00
notify["connection_connected_time"] = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now() - target->connectTimestamp).count();
notify["connection_idle_time"] = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now() - target->idleTimestamp).count();
this->sendCommand(notify);
return true;
}
bool ConnectedClient::notifyClientMoved(const shared_ptr<ConnectedClient> &client,
const std::shared_ptr<BasicChannel> &target_channel,
ViewReasonId reason,
std::string msg,
std::shared_ptr<ConnectedClient> invoker,
bool lock_channel_tree) {
2020-01-24 02:57:58 +01:00
assert(!lock_channel_tree);
assert(client->getClientId() > 0);
assert(client->currentChannel);
assert(target_channel);
assert(this->isClientVisible(client, false) || &*client == this);
Command mv("notifyclientmoved");
mv["clid"] = client->getClientId();
mv["cfid"] = client->currentChannel->channelId();
mv["ctid"] = target_channel->channelId();
mv["reasonid"] = reason;
if (invoker)
INVOKER(mv, invoker);
if (!msg.empty()) mv["reasonmsg"] = msg;
else mv["reasonmsg"] = "";
this->sendCommand(mv);
return true;
}
bool ConnectedClient::notifyClientUpdated(const std::shared_ptr<ConnectedClient> &client, const deque<shared_ptr<property::PropertyDescription>> &props, bool lock) {
2020-01-24 02:57:58 +01:00
shared_lock channel_lock(this->channel_lock, defer_lock);
if(lock)
channel_lock.lock();
if(!this->isClientVisible(client, false) && client != this)
return false;
auto client_id = client->getClientId();
if(client_id == 0) {
logError(this->getServerId(), "{} Attempted to send a clientupdate for client id 0. Updated client: {}", CLIENT_STR_LOG_PREFIX, CLIENT_STR_LOG_PREFIX_(client));
return false;
}
Command response("notifyclientupdated");
response["clid"] = client_id;
for (const auto &prop : props) {
if(lastOnlineTimestamp.time_since_epoch().count() > 0 && (prop->property_index == property::CLIENT_TOTAL_ONLINE_TIME || prop->property_index == property::CLIENT_MONTH_ONLINE_TIME))
response[prop->name] = client->properties()[prop].as<int64_t>() + duration_cast<seconds>(system_clock::now() - client->lastOnlineTimestamp).count();
else
response[prop->name] = client->properties()[prop].value();
}
this->sendCommand(response);
return true;
}
bool ConnectedClient::notifyPluginCmd(std::string name, std::string msg, std::shared_ptr<ConnectedClient> sender) {
Command notify("notifyplugincmd");
notify["name"] = name;
notify["data"] = msg;
INVOKER(notify, sender);
this->sendCommand(notify);
return true;
}
bool ConnectedClient::notifyClientChatComposing(const shared_ptr<ConnectedClient> &client) {
Command notify("notifyclientchatcomposing");
notify["clid"] = client->getClientId();
notify["cluid"] = client->getUid();
this->sendCommand(notify);
return true;
}
bool ConnectedClient::notifyClientChatClosed(const shared_ptr<ConnectedClient> &client) {
Command notify("notifyclientchatclosed");
notify["clid"] = client->getClientId();
notify["cluid"] = client->getUid();
this->sendCommand(notify);
return true;
}
bool ConnectedClient::notifyChannelMoved(const std::shared_ptr<BasicChannel> &channel, ChannelId order, const std::shared_ptr<ConnectedClient> &invoker) {
2020-01-24 02:57:58 +01:00
if(!channel || !this->channels->channel_visible(channel)) return false;
Command notify("notifychannelmoved");
INVOKER(notify, invoker);
notify["reasonid"] = ViewReasonId::VREASON_MOVED;
notify["cid"] = channel->channelId();
notify["cpid"] = channel->parent() ? channel->parent()->channelId() : 0;
notify["order"] = order;
this->sendCommand(notify);
return true;
}
bool ConnectedClient::notifyChannelCreate(const std::shared_ptr<BasicChannel> &channel, ChannelId orderId, const std::shared_ptr<ConnectedClient> &invoker) {
Command notify("notifychannelcreated");
for (auto &prop : channel->properties().list_properties(property::FLAG_CHANNEL_VARIABLE | property::FLAG_CHANNEL_VIEW, this->getType() == CLIENT_TEAMSPEAK ? property::FLAG_NEW : (uint16_t) 0)) {
if(prop.type() == property::CHANNEL_ORDER)
notify[prop.type().name] = orderId;
2019-11-10 18:31:40 +01:00
else if(prop.type() == property::CHANNEL_DESCRIPTION)
2020-01-24 02:57:58 +01:00
continue;
else
notify[prop.type().name] = prop.value();
}
INVOKER(notify, invoker);
this->sendCommand(notify);
return true;
}
bool ConnectedClient::notifyChannelHide(const std::deque<ChannelId> &channel_ids, bool lock_channel_tree) {
2020-01-24 02:57:58 +01:00
if(channel_ids.empty()) return true;
if(this->getType() == ClientType::CLIENT_TEAMSPEAK) { //Voice hasnt that event
shared_lock server_channel_lock(this->server->channel_tree_lock, defer_lock);
unique_lock client_channel_lock(this->channel_lock, defer_lock);
if(lock_channel_tree) {
server_channel_lock.lock();
client_channel_lock.lock();
} else {
assert(mutex_locked(this->channel_lock));
}
deque<shared_ptr<ConnectedClient>> clients_to_remove;
{
for(const auto& w_client : this->visibleClients) {
auto client = w_client.lock();
if(!client) continue;
if(client->currentChannel) {
auto id = client->currentChannel->channelId();
for(const auto cid : channel_ids) {
if(cid == id) {
clients_to_remove.push_back(client);
break;
}
}
}
}
}
//TODO: May send a unsubscribe and remove the clients like that?
this->notifyClientLeftView(clients_to_remove, "Channel gone out of view", false, ViewReasonServerLeft);
return this->notifyChannelDeleted(channel_ids, this->server->serverRoot);
} else {
Command notify("notifychannelhide");
int index = 0;
for(const auto& channel : channel_ids)
notify[index++]["cid"] = channel;
this->sendCommand(notify);
}
return true;
}
bool ConnectedClient::notifyChannelShow(const std::shared_ptr<ts::BasicChannel> &channel, ts::ChannelId orderId) {
2020-01-24 02:57:58 +01:00
if(!channel)
return false;
2020-01-24 02:57:58 +01:00
auto result = false;
if(this->getType() == ClientType::CLIENT_TEAMSPEAK) { //Voice hasn't that event
2020-01-24 02:57:58 +01:00
result = this->notifyChannelCreate(channel, orderId, this->server->serverRoot);
} else {
Command notify("notifychannelshow");
for (auto &prop : channel->properties().list_properties(property::FLAG_CHANNEL_VARIABLE | property::FLAG_CHANNEL_VIEW, this->getType() == CLIENT_TEAMSPEAK ? property::FLAG_NEW : (uint16_t) 0)) {
2019-11-10 18:31:40 +01:00
if(prop.type() == property::CHANNEL_ORDER) {
2020-01-24 02:57:58 +01:00
notify[prop.type().name] = orderId;
2019-11-10 18:31:40 +01:00
} else if(prop.type() == property::CHANNEL_DESCRIPTION) {
2020-01-24 02:57:58 +01:00
continue;
2019-11-10 18:31:40 +01:00
}
else
notify[prop.type().name] = prop.value();
}
this->sendCommand(notify);
}
if(result && this->subscribeToAll)
2020-01-24 02:57:58 +01:00
this->subscribeChannel({channel}, false, true);
return true;
}
bool ConnectedClient::notifyChannelDescriptionChanged(std::shared_ptr<BasicChannel> channel) {
2020-01-24 02:57:58 +01:00
if(!this->channels->channel_visible(channel)) return false;
Command notifyDesChanges("notifychanneldescriptionchanged");
notifyDesChanges["cid"] = channel->channelId();
this->sendCommand(notifyDesChanges);
return true;
}
bool ConnectedClient::notifyChannelPasswordChanged(std::shared_ptr<BasicChannel> channel) {
2020-01-24 02:57:58 +01:00
if(!this->channels->channel_visible(channel)) return false;
Command notifyDesChanges("notifychannelpasswordchanged");
notifyDesChanges["cid"] = channel->channelId();
this->sendCommand(notifyDesChanges);
return true;
}
bool ConnectedClient::notifyClientEnterView(const std::shared_ptr<ConnectedClient> &client, const std::shared_ptr<ConnectedClient> &invoker, const std::string& reason, const std::shared_ptr<BasicChannel> &to, ViewReasonId reasonId, const std::shared_ptr<BasicChannel> &from, bool lock_channel_tree) {
2020-01-24 02:57:58 +01:00
sassert(client && client->getClientId() > 0);
sassert(to);
sassert(!lock_channel_tree); /* we don't support locking */
sassert(!this->isClientVisible(client, false) || &*client == this);
switch (reasonId) {
case ViewReasonId::VREASON_MOVED:
case ViewReasonId::VREASON_BAN:
case ViewReasonId::VREASON_CHANNEL_KICK:
case ViewReasonId::VREASON_SERVER_KICK:
if(!invoker) {
logCritical(this->getServerId(), "{} ConnectedClient::notifyClientEnterView() => missing invoker for reason id {}", CLIENT_STR_LOG_PREFIX, reasonId);
if(this->server)
;//invoker = this->server->serverRoot.get();
}
break;
default:
break;
}
2020-01-24 02:57:58 +01:00
Command cmd("notifycliententerview");
2020-01-24 02:57:58 +01:00
cmd["cfid"] = from ? from->channelId() : 0;
cmd["ctid"] = to ? to->channelId() : 0;
cmd["reasonid"] = reasonId;
INVOKER(cmd, invoker);
switch (reasonId) {
case ViewReasonId::VREASON_MOVED:
case ViewReasonId::VREASON_BAN:
case ViewReasonId::VREASON_CHANNEL_KICK:
case ViewReasonId::VREASON_SERVER_KICK:
cmd["reasonmsg"] = reason;
break;
default:
break;
}
2020-01-24 02:57:58 +01:00
for (const auto &elm : client->properties()->list_properties(property::FLAG_CLIENT_VIEW, this->getType() == CLIENT_TEAMSPEAK ? property::FLAG_NEW : (uint16_t) 0)) {
cmd[elm.type().name] = elm.value();
}
2020-01-24 02:57:58 +01:00
visibleClients.emplace_back(client);
this->sendCommand(cmd);
2020-01-24 02:57:58 +01:00
return true;
}
2020-01-24 02:57:58 +01:00
bool ConnectedClient::notifyClientEnterView(const std::deque<std::shared_ptr<ConnectedClient>> &clients, const ts::ViewReasonSystemT &_vrs) {
if(clients.empty())
return true;
assert(mutex_locked(this->channel_lock));
Command cmd("notifycliententerview");
cmd["cfid"] = 0;
cmd["reasonid"] = ViewReasonId::VREASON_SYSTEM;
ChannelId current_channel = 0;
size_t index = 0;
auto it = clients.begin();
while(it != clients.end()) {
auto client = *(it++);
if(this->isClientVisible(client, false))
continue;
auto channel = client->getChannel();
sassert(!channel || channel->channelId() != 0);
if(!channel) /* hmm suspecious */
continue;
if(current_channel != channel->channelId()) {
if(current_channel == 0)
cmd[index]["ctid"] = (current_channel = channel->channelId());
else {
it--; /* we still have to send him */
break;
}
}
2020-01-24 02:57:58 +01:00
this->visibleClients.push_back(client);
for (const auto &elm : client->properties()->list_properties(property::FLAG_CLIENT_VIEW, this->getType() == CLIENT_TEAMSPEAK ? property::FLAG_NEW : (uint16_t) 0)) {
cmd[index][elm.type().name] = elm.value();
}
2020-01-24 02:57:58 +01:00
index++;
if(index > 16) /* max 16 clients per packet */
break;
}
2020-01-24 02:57:58 +01:00
if(index > 0)
this->sendCommand(cmd);
2020-01-24 02:57:58 +01:00
if(it != clients.end())
return this->notifyClientEnterView({it, clients.end()}, _vrs);
return true;
}
2019-11-10 18:31:40 +01:00
bool ConnectedClient::notifyChannelEdited(
2020-01-24 02:57:58 +01:00
const std::shared_ptr<BasicChannel> &channel,
const std::vector<property::ChannelProperties> &properties,
const std::shared_ptr<ConnectedClient> &invoker,
bool) {
auto v_channel = this->channels->find_channel(channel->channelId());
if(!v_channel) return false; //Not visible? Important do not remove!
bool send_description_change{false};
Command notify("notifychanneledited");
for(auto prop : properties) {
const auto& prop_info = property::impl::info(prop);
if(prop == property::CHANNEL_ORDER)
notify[prop_info->name] = v_channel->previous_channel;
else if(prop == property::CHANNEL_DESCRIPTION) {
send_description_change = true;
} else {
notify[prop_info->name] = channel->properties()[prop].as<string>();
}
}
2020-01-24 02:57:58 +01:00
notify["cid"] = channel->channelId();
notify["reasonid"] = ViewReasonId::VREASON_EDITED;
2020-01-24 02:57:58 +01:00
INVOKER(notify, invoker);
this->sendCommand(notify);
2019-11-10 18:31:40 +01:00
2020-01-24 02:57:58 +01:00
if(send_description_change) {
Command notify_dchange{"notifychanneldescriptionchanged"};
notify_dchange["cid"] = channel->channelId();
this->sendCommand(notify_dchange);
}
2019-11-10 18:31:40 +01:00
2020-01-24 02:57:58 +01:00
return true;
}
bool ConnectedClient::notifyChannelDeleted(const deque<ChannelId>& channel_ids, const std::shared_ptr<ConnectedClient>& invoker) {
2020-01-24 02:57:58 +01:00
if(channel_ids.empty())
return true;
2020-01-24 02:57:58 +01:00
Command notify("notifychanneldeleted");
int index = 0;
for (const auto& channel_id : channel_ids)
notify[index++]["cid"] = channel_id;
INVOKER(notify, invoker);
notify["reasonid"] = ViewReasonId::VREASON_EDITED;
this->sendCommand(notify);
return true;
}
bool ConnectedClient::notifyServerUpdated(std::shared_ptr<ConnectedClient> invoker) {
Command response("notifyserverupdated");
for (const auto& elm : this->server->properties().list_properties(property::FLAG_SERVER_VARIABLE, this->getType() == CLIENT_TEAMSPEAK ? property::FLAG_NEW : (uint16_t) 0)) {
2020-01-24 02:57:58 +01:00
if(elm.type() == property::VIRTUALSERVER_MIN_WINPHONE_VERSION)
continue;
2020-01-24 02:57:58 +01:00
//if(elm->type() == property::VIRTUALSERVER_RESERVED_SLOTS)
response[elm.type().name] = elm.value();
}
if(getType() == CLIENT_QUERY)
INVOKER(response, invoker);
this->sendCommand(response);
return true;
}
bool ConnectedClient::notifyClientPoke(std::shared_ptr<ConnectedClient> invoker, std::string msg) {
Command cmd("notifyclientpoke");
INVOKER(cmd, invoker);
cmd["msg"] = msg;
this->sendCommand(cmd);
return true;
}
bool ConnectedClient::notifyChannelSubscribed(const deque<shared_ptr<BasicChannel>> &channels) {
Command notify("notifychannelsubscribed");
int index = 0;
for (const auto& ch : channels) {
notify[index]["es"] = this->server->getClientsByChannel(ch).empty() ? ch->emptySince() : 0;
notify[index++]["cid"] = ch->channelId();
}
this->sendCommand(notify);
return true;
}
bool ConnectedClient::notifyChannelUnsubscribed(const deque<shared_ptr<BasicChannel>> &channels) {
Command notify("notifychannelunsubscribed");
int index = 0;
for (const auto& ch : channels) {
notify[index]["es"] = this->server->getClientsByChannel(ch).empty() ? ch->emptySince() : 0;
notify[index++]["cid"] = ch->channelId();
}
this->sendCommand(notify);
return true;
}
bool ConnectedClient::notifyMusicQueueAdd(const shared_ptr<MusicClient>& bot, const shared_ptr<ts::music::SongInfo>& entry, int index, const std::shared_ptr<ConnectedClient>& invoker) {
Command notify("notifymusicqueueadd");
notify["bot_id"] = bot->getClientDatabaseId();
notify["song_id"] = entry->getSongId();
notify["url"] = entry->getUrl();
notify["index"] = index;
2020-01-24 02:57:58 +01:00
INVOKER(notify, invoker);
this->sendCommand(notify);
return true;
}
bool ConnectedClient::notifyMusicQueueRemove(const std::shared_ptr<MusicClient> &bot, const std::deque<std::shared_ptr<music::SongInfo>> &entry, const std::shared_ptr<ConnectedClient>& invoker) {
2020-01-24 02:57:58 +01:00
Command notify("notifymusicqueueremove");
notify["bot_id"] = bot->getClientDatabaseId();
int index = 0;
for(const auto& song : entry)
notify[index++]["song_id"] = song->getSongId();
INVOKER(notify, invoker);
this->sendCommand(notify);
return true;
}
bool ConnectedClient::notifyMusicQueueOrderChange(const std::shared_ptr<MusicClient> &bot, const std::shared_ptr<ts::music::SongInfo> &entry, int order, const std::shared_ptr<ConnectedClient>& invoker) {
2020-01-24 02:57:58 +01:00
Command notify("notifymusicqueueorderchange");
notify["bot_id"] = bot->getClientDatabaseId();
notify["song_id"] = entry->getSongId();
notify["index"] = order;
INVOKER(notify, invoker);
this->sendCommand(notify);
return true;
}
bool ConnectedClient::notifyMusicPlayerStatusUpdate(const std::shared_ptr<ts::server::MusicClient> &bot) {
2020-01-24 02:57:58 +01:00
Command notify("notifymusicstatusupdate");
notify["bot_id"] = bot->getClientDatabaseId();
2020-01-24 02:57:58 +01:00
auto player = bot->current_player();
if(player) {
notify["player_buffered_index"] = player->bufferedUntil().count();
notify["player_replay_index"] = player->currentIndex().count();
} else {
notify["player_buffered_index"] = 0;
notify["player_replay_index"] = 0;
}
this->sendCommand(notify);
return true;
}
extern void apply_song(Command& command, const std::shared_ptr<ts::music::SongInfo>& element, int index = 0);
bool ConnectedClient::notifyMusicPlayerSongChange(const std::shared_ptr<MusicClient> &bot, const shared_ptr<music::SongInfo> &newEntry) {
2020-01-24 02:57:58 +01:00
Command notify("notifymusicplayersongchange");
notify["bot_id"] = bot->getClientDatabaseId();
2020-01-24 02:57:58 +01:00
if(newEntry) {
apply_song(notify, newEntry);
} else {
notify["song_id"] = 0;
}
this->sendCommand(notify);
return true;
2019-08-20 13:46:23 +02:00
}
bool ConnectedClient::notifyConversationMessageDelete(const ts::ChannelId channel_id, const std::chrono::system_clock::time_point& begin, const std::chrono::system_clock::time_point& end, ts::ClientDbId client_id, size_t size) {
2020-01-24 02:57:58 +01:00
Command notify("notifyconversationmessagedelete");
2019-08-20 13:46:23 +02:00
2020-01-24 02:57:58 +01:00
notify["cid"] = channel_id;
notify["timestamp_begin"] = floor<milliseconds>(begin.time_since_epoch()).count();
notify["timestamp_end"] = floor<milliseconds>(end.time_since_epoch()).count();
notify["cldbid"] = client_id;
notify["limit"] = size;
2019-08-20 13:46:23 +02:00
2020-01-24 02:57:58 +01:00
this->sendCommand(notify);
return true;
}