-/* Copyright (C) 2009-2011, Martin Johansson <martin@fatbob.nu>
- Copyright (C) 2005-2011, Thorvald Natvig <thorvald@natvig.com>
+/* Copyright (C) 2009-2014, Martin Johansson <martin@fatbob.nu>
+ Copyright (C) 2005-2014, Thorvald Natvig <thorvald@natvig.com>
All rights reserved.
#include "channel.h"
#include "conf.h"
#include "voicetarget.h"
+#include "ban.h"
#define MAX_TEXT 512
#define MAX_USERNAME 128
+#define NO_CELT_MESSAGE "<strong>WARNING:</strong> Your client doesn't support the CELT codec, you won't be able to talk to or hear most clients. Please make sure your client was built with CELT support."
+
+
extern channel_t *defaultChan;
extern int iCodecAlpha, iCodecBeta;
-extern bool_t bPreferAlpha;
+extern bool_t bPreferAlpha, bOpus;
+
+static bool_t fake_celt_support;
static void sendServerReject(client_t *client, const char *reason, MumbleProto__Reject__RejectType type)
{
if (strlen(getStrConf(ADMIN_PASSPHRASE)) > 0 &&
Client_token_match(client, getStrConf(ADMIN_PASSPHRASE))) {
client->isAdmin = true;
- Log_info("User is admin");
+ Log_info_client(client, "User provided admin password");
}
/* Setup UDP encryption */
Log_debug("Client %d CELT codec ver 0x%x", client->sessionId, codec_itr->codec);
} else {
- Client_codec_add(client, (int32_t)0x8000000a);
+ Client_codec_add(client, (int32_t)0x8000000b);
client->codec_count = 1;
+ fake_celt_support = true;
}
+ if (msg->payload.authenticate->opus)
+ client->bOpus = true;
- recheckCodecVersions();
+ recheckCodecVersions(client);
sendmsg = Msg_create(CodecVersion);
sendmsg->payload.codecVersion->alpha = iCodecAlpha;
sendmsg->payload.codecVersion->beta = iCodecBeta;
sendmsg->payload.codecVersion->prefer_alpha = bPreferAlpha;
+ sendmsg->payload.codecVersion->has_opus = true;
+ sendmsg->payload.codecVersion->opus = bOpus;
Client_send_message(client, sendmsg);
-
+
+ if (!bOpus && client->bOpus && fake_celt_support) {
+ Client_textmessage(client, NO_CELT_MESSAGE);
+ }
+
/* Iterate channels and send channel info */
ch_itr = NULL;
while (Chan_iterate(&ch_itr) != NULL) {
sendmsg->payload.channelState->name = strdup(ch_itr->name);
if (ch_itr->desc)
sendmsg->payload.channelState->description = strdup(ch_itr->desc);
+ if (ch_itr->position != 0) {
+ sendmsg->payload.channelState->has_position = true;
+ sendmsg->payload.channelState->position = ch_itr->position;
+ }
Log_debug("Send channel info: %s", sendmsg->payload.channelState->name);
Client_send_message(client, sendmsg);
}
sendmsg->payload.userState->has_channel_id = true;
sendmsg->payload.userState->channel_id = ((channel_t *)client->channel)->id;
+ if (defaultChan->silent) {
+ sendmsg->payload.userState->has_suppress = true;
+ sendmsg->payload.userState->suppress = true;
+ }
+
Client_send_message_except(client, sendmsg);
client_itr = NULL;
sendmsg->payload.userState->name = strdup(client_itr->username);
sendmsg->payload.userState->has_channel_id = true;
sendmsg->payload.userState->channel_id = ((channel_t *)client_itr->channel)->id;
+ sendmsg->payload.userState->has_suppress = ((channel_t *)client_itr->channel)->silent;
+ sendmsg->payload.userState->suppress = ((channel_t *)client_itr->channel)->silent;
- /* Only self_mute/deaf supported */
- if (client_itr->deaf) {
+ client_itr->isSuppressed = ((channel_t *)client_itr->channel)->silent;
+
+ if (client_itr->self_deaf) {
sendmsg->payload.userState->has_self_deaf = true;
sendmsg->payload.userState->self_deaf = true;
}
- if (client_itr->mute) {
+ if (client_itr->self_mute) {
sendmsg->payload.userState->has_self_mute = true;
sendmsg->payload.userState->self_mute = true;
}
+ if (client_itr->deaf) {
+ sendmsg->payload.userState->has_deaf = true;
+ sendmsg->payload.userState->deaf = true;
+ }
+ if (client_itr->mute) {
+ sendmsg->payload.userState->has_mute = true;
+ sendmsg->payload.userState->mute = true;
+ }
if (client_itr->recording) {
sendmsg->payload.userState->has_recording = true;
sendmsg->payload.userState->recording = true;
if (!target->mute) {
msg->payload.userState->has_deaf = true;
msg->payload.userState->deaf = false;
- client->deaf = false;
+ target->deaf = false;
}
}
if (msg->payload.userState->has_self_deaf) {
- client->deaf = msg->payload.userState->self_deaf;
+ client->self_deaf = msg->payload.userState->self_deaf;
+ if (client->self_deaf) {
+ msg->payload.userState->has_self_mute = true;
+ msg->payload.userState->self_mute = true;
+ }
}
if (msg->payload.userState->has_self_mute) {
- client->mute = msg->payload.userState->self_mute;
- if (!client->mute) {
+ client->self_mute = msg->payload.userState->self_mute;
+ if (!client->self_mute) {
msg->payload.userState->has_self_deaf = true;
msg->payload.userState->self_deaf = false;
- client->deaf = false;
+ client->self_deaf = false;
}
}
if (msg->payload.userState->has_recording &&
}
if (msg->payload.userState->has_channel_id) {
int leave_id;
- channelJoinResult_t chjoin_rc = Chan_userJoin_id_test(msg->payload.userState->channel_id, client);
-
- if (chjoin_rc != CHJOIN_OK) {
- if (chjoin_rc == CHJOIN_WRONGPW) {
+
+ channelJoinResult_t result = Chan_userJoin_id_test(msg->payload.userState->channel_id, target);
+
+ if (result.CHJOIN_NOENTER || result.CHJOIN_NOTFOUND)
+ break;
+
+ if (result.CHJOIN_WRONGPW) {
+ if (target == client && !client->isAdmin) {
sendPermissionDenied(client, "Wrong channel password");
+ break;
}
- break;
+ /* Tricky one: if user hasn't the password, but is moved to the channel by admin then let
+ * the user in. Also let admin user in regardless of channel password.
+ * Take no action on other errors.
+ */
+ else if (!client->isAdmin)
+ break;
}
-
- leave_id = Chan_userJoin_id(msg->payload.userState->channel_id, client);
+
+ leave_id = Chan_userJoin_id(msg->payload.userState->channel_id, target);
if (leave_id > 0) {
Log_debug("Removing channel ID %d", leave_id);
sendmsg = Msg_create(ChannelRemove);
sendmsg->payload.channelRemove->channel_id = leave_id;
}
+
+ if (result.CHJOIN_SILENT) {
+ if (!target->isSuppressed) {
+ msg->payload.userState->has_suppress = true;
+ msg->payload.userState->suppress = true;
+ target->isSuppressed = true;
+ }
+ }
+ else if (target->isSuppressed) {
+ msg->payload.userState->has_suppress = true;
+ msg->payload.userState->suppress = false;
+ target->isSuppressed = false;
+ }
}
if (msg->payload.userState->has_plugin_context) {
if (client->context)
list_iterate(itr, &ch_itr->clients) {
client_t *c;
c = list_get_entry(itr, client_t, chan_node);
- if (c != client && !c->deaf) {
+ if (c != client && !c->deaf && !c->self_deaf) {
Msg_inc_ref(msg);
Client_send_message(c, msg);
Log_debug("Text message to session ID %d", c->sessionId);
if (!IS_AUTH(itr))
continue;
if (itr->sessionId == msg->payload.textMessage->session[i]) {
- if (!itr->deaf) {
+ if (!itr->deaf && !itr->self_deaf) {
Msg_inc_ref(msg);
Client_send_message(itr, msg);
Log_debug("Text message to session ID %d", itr->sessionId);
if (!getBoolConf(ALLOW_TEXTMESSAGE))
msg->payload.permissionQuery->permissions &= ~PERM_TEXTMESSAGE;
+ if (!getBoolConf(ENABLE_BAN))
+ msg->payload.permissionQuery->permissions &= ~PERM_BAN;
Client_send_message(client, msg);
break;
newchan = Chan_createChannel(msg->payload.channelState->name,
msg->payload.channelState->description);
newchan->temporary = true;
+ if (msg->payload.channelState->has_position)
+ newchan->position = msg->payload.channelState->position;
Chan_addChannel(parent, newchan);
msg->payload.channelState->has_channel_id = true;
msg->payload.channelState->channel_id = newchan->id;
sendmsg->payload.userState->session = client->sessionId;
sendmsg->payload.userState->has_channel_id = true;
sendmsg->payload.userState->channel_id = newchan->id;
+
+ if (client->isSuppressed) {
+ sendmsg->payload.userState->has_suppress = true;
+ sendmsg->payload.userState->suppress = false;
+ client->isSuppressed = false;
+ }
+
Client_send_message_except(NULL, sendmsg);
-
+
leave_id = Chan_userJoin(newchan, client);
if (leave_id > 0) {
Log_debug("Removing channel ID %d", leave_id);
sendmsg->payload.userStats->version->has_version = true;
sendmsg->payload.userStats->version->version = target->version;
- sendmsg->payload.userStats->version->release = strdup(target->release);
- sendmsg->payload.userStats->version->os = strdup(target->os);
- sendmsg->payload.userStats->version->os_version = strdup(target->os_version);
+ if (target->release)
+ sendmsg->payload.userStats->version->release = strdup(target->release);
+ if (target->os)
+ sendmsg->payload.userStats->version->os = strdup(target->os);
+ if (target->os_version)
+ sendmsg->payload.userStats->version->os_version = strdup(target->os_version);
sendmsg->payload.userStats->n_celt_versions = target->codec_count;
sendmsg->payload.userStats->celt_versions = malloc(sizeof(int32_t) * target->codec_count);
while (Client_codec_iterate(target, &codec_itr) != NULL)
sendmsg->payload.userStats->celt_versions[i++] = codec_itr->codec;
+ sendmsg->payload.userStats->has_opus = true;
+ sendmsg->payload.userStats->opus = target->bOpus;
+
/* Address */
sendmsg->payload.userStats->has_address = true;
sendmsg->payload.userStats->address.data = malloc(sizeof(uint8_t) * 16);
memset(sendmsg->payload.userStats->address.data, 0, 16);
/* ipv4 representation as ipv6 address. Supposedly correct. */
memcpy(&sendmsg->payload.userStats->address.data[12], &target->remote_tcp.sin_addr, 4);
+ memset(&sendmsg->payload.userStats->address.data[10], 0xff, 2); /* IPv4 */
sendmsg->payload.userStats->address.len = 16;
}
/* BW */
msg->payload.userRemove->actor = client->sessionId;
if (msg->payload.userRemove->has_ban && msg->payload.userRemove->ban) {
- Ban_UserBan(target, msg->payload.userRemove->reason);
+ if (!getBoolConf(ENABLE_BAN))
+ sendPermissionDenied(client, "Permission denied");
+ else
+ Ban_UserBan(target, msg->payload.userRemove->reason);
} else {
- Log_info("User kicked");
+ Log_info_client(target, "User kicked. Reason: '%s'",
+ strlen(msg->payload.userRemove->reason) == 0 ? "N/A" : msg->payload.userRemove->reason);
}
/* Re-use message */
Msg_inc_ref(msg);
Client_send_message_except(NULL, msg);
Client_close(target);
break;
+ case BanList:
+ /* Only admin can issue this */
+ if (!client->isAdmin) {
+ sendPermissionDenied(client, "Permission denied");
+ break;
+ }
+ if (!getBoolConf(ENABLE_BAN)) {
+ sendPermissionDenied(client, "Permission denied");
+ break;
+ }
+ if (msg->payload.banList->has_query && msg->payload.banList->query) {
+ /* Create banlist message and add banentrys */
+ sendmsg = Ban_getBanList();
+ Client_send_message(client, sendmsg);
+ } else {
+ /* Clear banlist and set the new one */
+ Ban_clearBanList();
+ Ban_putBanList(msg, msg->payload.banList->n_bans);
+ }
+ break;
/* Permission denied for all these messages. Not implemented. */
case ChannelRemove:
case ContextAction:
case ContextActionAdd:
case ACL:
- case BanList:
case UserList:
case QueryUsers:
sendPermissionDenied(client, "Not supported by uMurmur");