1 /* Copyright (C) 2009-2011, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2011, Thorvald Natvig <thorvald@natvig.com>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
10 - Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 - Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15 - Neither the name of the Developers nor the names of its contributors may
16 be used to endorse or promote products derived from this software without
17 specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #include "messagehandler.h"
42 #include "voicetarget.h"
45 #define MAX_USERNAME 128
47 extern channel_t *defaultChan;
48 extern int iCodecAlpha, iCodecBeta;
49 extern bool_t bPreferAlpha;
51 static void sendServerReject(client_t *client, const char *reason, MumbleProto__Reject__RejectType type)
53 message_t *msg = Msg_create(Reject);
54 msg->payload.reject->reason = strdup(reason);
55 msg->payload.reject->type = type;
56 msg->payload.reject->has_type = true;
57 Client_send_message(client, msg);
59 Log_info_client(client, "Server reject reason: %s", reason);
62 static void sendPermissionDenied(client_t *client, const char *reason)
64 message_t *msg = Msg_create(PermissionDenied);
65 msg->payload.permissionDenied->has_type = true;
66 msg->payload.permissionDenied->type = MUMBLE_PROTO__PERMISSION_DENIED__DENY_TYPE__Text;
67 msg->payload.permissionDenied->reason = strdup(reason);
68 Client_send_message(client, msg);
71 static void addTokens(client_t *client, message_t *msg)
74 if (client->tokencount + msg->payload.authenticate->n_tokens < MAX_TOKENS) {
75 /* Check lengths first */
76 for (i = 0; i < msg->payload.authenticate->n_tokens; i++) {
77 if (strlen(msg->payload.authenticate->tokens[i]) > MAX_TOKENSIZE - 1) {
78 sendPermissionDenied(client, "Too long token");
83 for (i = 0; i < msg->payload.authenticate->n_tokens; i++) {
84 Log_debug("Adding token '%s' to client '%s'", msg->payload.authenticate->tokens[i], client->username);
85 Client_token_add(client, msg->payload.authenticate->tokens[i]);
89 sendPermissionDenied(client, "Too many tokens");
92 void Mh_handle_message(client_t *client, message_t *msg)
94 message_t *sendmsg = NULL;
95 channel_t *ch_itr = NULL;
96 client_t *client_itr, *target;
98 if (!client->authenticated && !(msg->messageType == Authenticate ||
99 msg->messageType == Version)) {
103 switch (msg->messageType) {
109 case PermissionQuery:
112 Timer_restart(&client->idleTime);
115 switch (msg->messageType) {
117 Log_debug("Authenticate message received");
119 if (IS_AUTH(client) || !msg->payload.authenticate->username) {
120 /* Authenticate message might be sent when a tokens are changed by the user.*/
121 Client_token_free(client); /* Clear the token list */
122 if (msg->payload.authenticate->n_tokens > 0) {
123 Log_debug("Tokens in auth message from '%s'. n_tokens = %d", client->username,
124 msg->payload.authenticate->n_tokens);
125 addTokens(client, msg);
130 if (SSLi_getSHA1Hash(client->ssl, client->hash) && Ban_isBanned(client)) {
132 SSLi_hash2hex(client->hash, hexhash);
133 Log_info("Client with hash '%s' is banned. Disconnecting", hexhash);
137 client->authenticated = true;
140 while (Client_iterate(&client_itr) != NULL) {
141 if (!IS_AUTH(client_itr))
143 if (client_itr->username && strncmp(client_itr->username, msg->payload.authenticate->username, MAX_USERNAME) == 0) {
145 sprintf(buf, "Username already in use");
146 Log_debug("Username already in use");
147 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__UsernameInUse);
151 if (strlen(getStrConf(PASSPHRASE)) > 0) {
152 if (!msg->payload.authenticate->password ||
153 (msg->payload.authenticate->password &&
154 strncmp(getStrConf(PASSPHRASE), msg->payload.authenticate->password, MAX_TEXT) != 0)) {
156 sprintf(buf, "Wrong server password");
157 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__WrongServerPW);
158 Log_debug("Wrong server password: '%s'", msg->payload.authenticate->password != NULL ?
159 msg->payload.authenticate->password : "(null)");
163 if (strlen(msg->payload.authenticate->username) == 0 ||
164 strlen(msg->payload.authenticate->username) >= MAX_USERNAME) { /* XXX - other invalid names? */
166 sprintf(buf, "Invalid username");
167 Log_debug("Invalid username");
168 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__InvalidUsername);
172 if (Client_count() >= getIntConf(MAX_CLIENTS)) {
174 snprintf(buf, 64, "Server is full (max %d users)", getIntConf(MAX_CLIENTS));
175 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__ServerFull);
180 client->username = strdup(msg->payload.authenticate->username);
183 if (msg->payload.authenticate->n_tokens > 0)
184 addTokens(client, msg);
186 /* Check if admin PW among tokens */
187 if (strlen(getStrConf(ADMIN_PASSPHRASE)) > 0 &&
188 Client_token_match(client, getStrConf(ADMIN_PASSPHRASE))) {
189 client->isAdmin = true;
190 Log_info("User is admin");
193 /* Setup UDP encryption */
194 CryptState_init(&client->cryptState);
195 CryptState_genKey(&client->cryptState);
196 sendmsg = Msg_create(CryptSetup);
197 sendmsg->payload.cryptSetup->has_key = true;
198 sendmsg->payload.cryptSetup->key.data = client->cryptState.raw_key;
199 sendmsg->payload.cryptSetup->key.len = AES_BLOCK_SIZE;
200 sendmsg->payload.cryptSetup->has_server_nonce = true;
201 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.encrypt_iv;
202 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
203 sendmsg->payload.cryptSetup->has_client_nonce = true;
204 sendmsg->payload.cryptSetup->client_nonce.data = client->cryptState.decrypt_iv;
205 sendmsg->payload.cryptSetup->client_nonce.len = AES_BLOCK_SIZE;
206 Client_send_message(client, sendmsg);
209 Chan_userJoin(defaultChan, client); /* Join default channel */
212 Log_debug("Client %d has %d CELT codecs", client->sessionId,
213 msg->payload.authenticate->n_celt_versions);
214 if (msg->payload.authenticate->n_celt_versions > 0) {
217 client->codec_count = msg->payload.authenticate->n_celt_versions;
219 for (i = 0; i < client->codec_count; i++)
220 Client_codec_add(client, msg->payload.authenticate->celt_versions[i]);
222 while (Client_codec_iterate(client, &codec_itr) != NULL)
223 Log_debug("Client %d CELT codec ver 0x%x", client->sessionId, codec_itr->codec);
226 Client_codec_add(client, (int32_t)0x8000000a);
227 client->codec_count = 1;
230 recheckCodecVersions();
232 sendmsg = Msg_create(CodecVersion);
233 sendmsg->payload.codecVersion->alpha = iCodecAlpha;
234 sendmsg->payload.codecVersion->beta = iCodecBeta;
235 sendmsg->payload.codecVersion->prefer_alpha = bPreferAlpha;
236 Client_send_message(client, sendmsg);
238 /* Iterate channels and send channel info */
240 while (Chan_iterate(&ch_itr) != NULL) {
241 sendmsg = Msg_create(ChannelState);
242 sendmsg->payload.channelState->has_channel_id = true;
243 sendmsg->payload.channelState->channel_id = ch_itr->id;
244 if (ch_itr->id != 0) {
245 sendmsg->payload.channelState->has_parent = true;
246 sendmsg->payload.channelState->parent = ch_itr->parent->id;
248 sendmsg->payload.channelState->name = strdup(ch_itr->name);
250 sendmsg->payload.channelState->description = strdup(ch_itr->desc);
251 Log_debug("Send channel info: %s", sendmsg->payload.channelState->name);
252 Client_send_message(client, sendmsg);
255 /* Iterate channels and send channel links info */
257 while (Chan_iterate(&ch_itr) != NULL) {
258 if (ch_itr->linkcount > 0) { /* Has links */
263 sendmsg = Msg_create(ChannelState);
264 sendmsg->payload.channelState->has_channel_id = true;
265 sendmsg->payload.channelState->channel_id = ch_itr->id;
266 sendmsg->payload.channelState->n_links = ch_itr->linkcount;
268 links = (uint32_t *)malloc(ch_itr->linkcount * sizeof(uint32_t));
269 list_iterate(itr, &ch_itr->channel_links) { /* Iterate links */
271 ch = list_get_entry(itr, channel_t, link_node);
274 sendmsg->payload.channelState->links = links;
275 Client_send_message(client, sendmsg);
279 /* Send user state for connecting user to other users */
280 sendmsg = Msg_create(UserState);
281 sendmsg->payload.userState->has_session = true;
282 sendmsg->payload.userState->session = client->sessionId;
283 sendmsg->payload.userState->name = strdup(client->username);
284 sendmsg->payload.userState->has_channel_id = true;
285 sendmsg->payload.userState->channel_id = ((channel_t *)client->channel)->id;
287 Client_send_message_except(client, sendmsg);
290 while (Client_iterate(&client_itr) != NULL) {
291 if (!IS_AUTH(client_itr))
293 sendmsg = Msg_create(UserState);
294 sendmsg->payload.userState->has_session = true;
295 sendmsg->payload.userState->session = client_itr->sessionId;
296 sendmsg->payload.userState->name = strdup(client_itr->username);
297 sendmsg->payload.userState->has_channel_id = true;
298 sendmsg->payload.userState->channel_id = ((channel_t *)client_itr->channel)->id;
300 /* Only self_mute/deaf supported */
301 if (client_itr->deaf) {
302 sendmsg->payload.userState->has_self_deaf = true;
303 sendmsg->payload.userState->self_deaf = true;
305 if (client_itr->mute) {
306 sendmsg->payload.userState->has_self_mute = true;
307 sendmsg->payload.userState->self_mute = true;
309 if (client_itr->recording) {
310 sendmsg->payload.userState->has_recording = true;
311 sendmsg->payload.userState->recording = true;
313 Client_send_message(client, sendmsg);
317 sendmsg = Msg_create(ServerSync);
318 sendmsg->payload.serverSync->has_session = true;
319 sendmsg->payload.serverSync->session = client->sessionId;
320 sendmsg->payload.serverSync->welcome_text = strdup(getStrConf(WELCOMETEXT));
321 sendmsg->payload.serverSync->has_max_bandwidth = true;
322 sendmsg->payload.serverSync->max_bandwidth = getIntConf(MAX_BANDWIDTH);
323 Client_send_message(client, sendmsg);
325 /* Server config message */
326 sendmsg = Msg_create(ServerConfig);
327 sendmsg->payload.serverConfig->has_allow_html = true;
328 sendmsg->payload.serverConfig->allow_html = true; /* Support this? */
329 sendmsg->payload.serverConfig->has_message_length = true;
330 sendmsg->payload.serverConfig->message_length = MAX_TEXT; /* Hardcoded */
331 sendmsg->payload.serverConfig->has_image_message_length = true;
332 sendmsg->payload.serverConfig->image_message_length = 0; /* XXX */
333 Client_send_message(client, sendmsg);
335 Log_info_client(client, "User %s authenticated", client->username);
339 if (msg->payload.ping->has_good)
340 client->cryptState.uiRemoteGood = msg->payload.ping->good;
341 if (msg->payload.ping->has_late)
342 client->cryptState.uiRemoteLate = msg->payload.ping->late;
343 if (msg->payload.ping->has_lost)
344 client->cryptState.uiRemoteLost = msg->payload.ping->lost;
345 if (msg->payload.ping->has_resync)
346 client->cryptState.uiRemoteResync = msg->payload.ping->resync;
348 Log_debug("Ping <-: %d %d %d %d",
349 client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate,
350 client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync
353 client->UDPPingAvg = msg->payload.ping->udp_ping_avg;
354 client->UDPPingVar = msg->payload.ping->udp_ping_var;
355 client->TCPPingAvg = msg->payload.ping->tcp_ping_avg;
356 client->TCPPingVar = msg->payload.ping->tcp_ping_var;
357 client->UDPPackets = msg->payload.ping->udp_packets;
358 client->TCPPackets = msg->payload.ping->tcp_packets;
360 sendmsg = Msg_create(Ping);
362 sendmsg->payload.ping->timestamp = msg->payload.ping->timestamp;
363 sendmsg->payload.ping->has_timestamp = true;
364 sendmsg->payload.ping->good = client->cryptState.uiGood;
365 sendmsg->payload.ping->has_good = true;
366 sendmsg->payload.ping->late = client->cryptState.uiLate;
367 sendmsg->payload.ping->has_late = true;
368 sendmsg->payload.ping->lost = client->cryptState.uiLost;
369 sendmsg->payload.ping->has_lost = true;
370 sendmsg->payload.ping->resync = client->cryptState.uiResync;
371 sendmsg->payload.ping->has_resync = true;
373 Client_send_message(client, sendmsg);
374 Log_debug("Ping ->: %d %d %d %d",
375 client->cryptState.uiGood, client->cryptState.uiLate,
376 client->cryptState.uiLost, client->cryptState.uiResync);
380 Log_debug("Voice channel crypt resync requested");
381 if (!msg->payload.cryptSetup->has_client_nonce) {
382 sendmsg = Msg_create(CryptSetup);
383 sendmsg->payload.cryptSetup->has_server_nonce = true;
384 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.decrypt_iv;
385 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
386 Client_send_message(client, sendmsg);
388 memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSetup->client_nonce.data, AES_BLOCK_SIZE);
389 client->cryptState.uiResync++;
394 /* Only allow state changes for for the self user unless an admin is issuing */
395 if (msg->payload.userState->has_session &&
396 msg->payload.userState->session != client->sessionId && !client->isAdmin) {
397 sendPermissionDenied(client, "Permission denied");
400 if (msg->payload.userState->has_session && msg->payload.userState->session != client->sessionId) {
401 while (Client_iterate(&target) != NULL) {
402 if (target->sessionId == msg->payload.userState->session)
405 if (target == NULL) {
406 Log_warn("Client with sessionID %d not found", msg->payload.userState->session);
411 if (msg->payload.userState->has_user_id || msg->payload.userState->has_suppress ||
412 msg->payload.userState->has_priority_speaker || msg->payload.userState->has_texture) {
413 sendPermissionDenied(client, "Not supported by uMurmur");
420 msg->payload.userState->has_session = true;
421 msg->payload.userState->session = target->sessionId;
422 msg->payload.userState->has_actor = true;
423 msg->payload.userState->actor = client->sessionId;
425 if (msg->payload.userState->has_deaf) {
426 target->deaf = msg->payload.userState->deaf;
428 msg->payload.userState->has_mute = true;
429 msg->payload.userState->mute = true;
432 if (msg->payload.userState->has_mute) {
433 target->mute = msg->payload.userState->mute;
435 msg->payload.userState->has_deaf = true;
436 msg->payload.userState->deaf = false;
437 client->deaf = false;
440 if (msg->payload.userState->has_self_deaf) {
441 client->deaf = msg->payload.userState->self_deaf;
443 if (msg->payload.userState->has_self_mute) {
444 client->mute = msg->payload.userState->self_mute;
446 msg->payload.userState->has_self_deaf = true;
447 msg->payload.userState->self_deaf = false;
448 client->deaf = false;
451 if (msg->payload.userState->has_recording &&
452 msg->payload.userState->recording != client->recording) {
453 client->recording = msg->payload.userState->recording;
457 message = malloc(strlen(client->username) + 32);
459 Log_fatal("Out of memory");
460 tree_id = malloc(sizeof(uint32_t));
462 Log_fatal("Out of memory");
464 sendmsg = Msg_create(TextMessage);
465 sendmsg->payload.textMessage->message = message;
466 sendmsg->payload.textMessage->n_tree_id = 1;
467 sendmsg->payload.textMessage->tree_id = tree_id;
468 if (client->recording)
469 sprintf(message, "User %s started recording", client->username);
471 sprintf(message, "User %s stopped recording", client->username);
472 Client_send_message_except_ver(NULL, sendmsg, ~0x010203);
475 if (msg->payload.userState->has_channel_id) {
477 channelJoinResult_t chjoin_rc = Chan_userJoin_id_test(msg->payload.userState->channel_id, client);
479 if (chjoin_rc != CHJOIN_OK) {
480 if (chjoin_rc == CHJOIN_WRONGPW) {
481 sendPermissionDenied(client, "Wrong channel password");
486 leave_id = Chan_userJoin_id(msg->payload.userState->channel_id, client);
488 Log_debug("Removing channel ID %d", leave_id);
489 sendmsg = Msg_create(ChannelRemove);
490 sendmsg->payload.channelRemove->channel_id = leave_id;
493 if (msg->payload.userState->has_plugin_context) {
495 free(client->context);
496 client->context = malloc(msg->payload.userState->plugin_context.len);
497 if (client->context == NULL)
498 Log_fatal("Out of memory");
499 memcpy(client->context, msg->payload.userState->plugin_context.data,
500 msg->payload.userState->plugin_context.len);
502 break; /* Don't inform other users about this state */
507 Client_send_message_except(NULL, msg);
509 /* Need to send remove channel message _after_ UserState message */
511 Client_send_message_except(NULL, sendmsg);
515 msg->payload.textMessage->has_actor = true;
516 msg->payload.textMessage->actor = client->sessionId;
518 /* XXX - HTML is allowed and can't be turned off */
519 if (msg->payload.textMessage->n_tree_id > 0) {
520 sendPermissionDenied(client, "Tree message not supported");
524 if (msg->payload.textMessage->n_channel_id > 0) { /* To channel */
527 for (i = 0; i < msg->payload.textMessage->n_channel_id; i++) {
530 Chan_iterate(&ch_itr);
531 } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage->channel_id[i]);
532 if (ch_itr != NULL) {
534 list_iterate(itr, &ch_itr->clients) {
536 c = list_get_entry(itr, client_t, chan_node);
537 if (c != client && !c->deaf) {
539 Client_send_message(c, msg);
540 Log_debug("Text message to session ID %d", c->sessionId);
546 if (msg->payload.textMessage->n_session > 0) { /* To user */
549 for (i = 0; i < msg->payload.textMessage->n_session; i++) {
551 while (Client_iterate(&itr) != NULL) {
554 if (itr->sessionId == msg->payload.textMessage->session[i]) {
557 Client_send_message(itr, msg);
558 Log_debug("Text message to session ID %d", itr->sessionId);
564 Log_warn("TextMessage: Session ID %d not found", msg->payload.textMessage->session[i]);
571 int i, j, count, targetId = msg->payload.voiceTarget->id;
572 struct _MumbleProto__VoiceTarget__Target *target;
574 if (!targetId || targetId >= 0x1f)
576 Voicetarget_add_id(client, targetId);
577 count = msg->payload.voiceTarget->n_targets;
580 for (i = 0; i < count; i++) {
581 target = msg->payload.voiceTarget->targets[i];
582 for (j = 0; j < target->n_session; j++)
583 Voicetarget_add_session(client, targetId, target->session[j]);
584 if (target->has_channel_id) {
585 bool_t linked = false, children = false;
586 if (target->has_links)
587 linked = target->links;
588 if (target->has_children)
589 children = target->children;
590 Voicetarget_add_channel(client, targetId, target->channel_id, linked, children);
596 Log_debug("Version message received");
597 if (msg->payload.version->has_version) {
598 client->version = msg->payload.version->version;
599 Log_debug("Client version 0x%x", client->version);
601 if (msg->payload.version->release) {
602 if (client->release) free(client->release);
603 client->release = strdup(msg->payload.version->release);
604 Log_debug("Client release %s", client->release);
606 if (msg->payload.version->os) {
607 if (client->os) free(client->os);
608 client->os = strdup(msg->payload.version->os);
609 Log_debug("Client OS %s", client->os);
611 if (msg->payload.version->os_version) {
612 if (client->os_version) free(client->os_version);
613 client->os_version = strdup(msg->payload.version->os_version);
614 Log_debug("Client OS version %s", client->os_version);
617 case PermissionQuery:
618 Msg_inc_ref(msg); /* Re-use message */
619 msg->payload.permissionQuery->has_permissions = true;
621 msg->payload.permissionQuery->permissions = PERM_ADMIN;
623 msg->payload.permissionQuery->permissions = PERM_DEFAULT;
625 Client_send_message(client, msg);
628 client->bUDP = false;
629 Client_voiceMsg(client, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
633 channel_t *ch_itr, *parent, *newchan;
635 /* Don't allow any changes to existing channels */
636 if (msg->payload.channelState->has_channel_id) {
637 sendPermissionDenied(client, "Not supported by uMurmur");
640 /* Must have parent */
641 if (!msg->payload.channelState->has_parent) {
642 sendPermissionDenied(client, "Not supported by uMurmur");
646 if (msg->payload.channelState->name == NULL) {
647 sendPermissionDenied(client, "Not supported by uMurmur");
650 /* Must be temporary channel */
651 if (msg->payload.channelState->temporary != true) {
652 sendPermissionDenied(client, "Only temporary channels are supported by uMurmur");
655 /* Check channel name is OK */
656 if (strlen(msg->payload.channelState->name) > MAX_TEXT) {
657 sendPermissionDenied(client, "Channel name too long");
661 parent = Chan_fromId(msg->payload.channelState->parent);
665 while (Chan_iterate_siblings(parent, &ch_itr) != NULL) {
666 if (strcmp(ch_itr->name, msg->payload.channelState->name) == 0) {
667 sendPermissionDenied(client, "Channel already exists");
674 /* Disallow temporary channels as siblings to temporary channels */
675 if (parent->temporary) {
676 sendPermissionDenied(client, "Parent channel is temporary channel");
680 /* XXX - Murmur looks for "\\w" and sends perm denied if not found.
681 * I don't know why so I don't do that here...
684 /* Create the channel */
685 newchan = Chan_createChannel(msg->payload.channelState->name,
686 msg->payload.channelState->description);
687 newchan->temporary = true;
688 Chan_addChannel(parent, newchan);
689 msg->payload.channelState->has_channel_id = true;
690 msg->payload.channelState->channel_id = newchan->id;
692 Client_send_message_except(NULL, msg);
694 /* Join the creating user */
695 sendmsg = Msg_create(UserState);
696 sendmsg->payload.userState->has_session = true;
697 sendmsg->payload.userState->session = client->sessionId;
698 sendmsg->payload.userState->has_channel_id = true;
699 sendmsg->payload.userState->channel_id = newchan->id;
700 Client_send_message_except(NULL, sendmsg);
702 leave_id = Chan_userJoin(newchan, client);
704 Log_debug("Removing channel ID %d", leave_id);
705 sendmsg = Msg_create(ChannelRemove);
706 sendmsg->payload.channelRemove->channel_id = leave_id;
707 Client_send_message_except(NULL, sendmsg);
714 client_t *target = NULL;
715 codec_t *codec_itr = NULL;
717 bool_t details = true;
719 if (msg->payload.userStats->has_stats_only)
720 details = !msg->payload.userStats->stats_only;
722 if (!msg->payload.userStats->has_session)
723 sendPermissionDenied(client, "Not supported by uMurmur");
724 while (Client_iterate(&target) != NULL) {
725 if (!IS_AUTH(target))
727 if (target->sessionId == msg->payload.userStats->session)
730 if (!target) /* Not found */
734 * Differences from Murmur:
735 * o Ignoring certificates intentionally
736 * o Ignoring channel local determining
739 sendmsg = Msg_create(UserStats);
740 sendmsg->payload.userStats->session = msg->payload.userStats->session;
741 sendmsg->payload.userStats->from_client->has_good = true;
742 sendmsg->payload.userStats->from_client->good = target->cryptState.uiGood;
743 sendmsg->payload.userStats->from_client->has_late = true;
744 sendmsg->payload.userStats->from_client->late = target->cryptState.uiLate;
745 sendmsg->payload.userStats->from_client->has_lost = true;
746 sendmsg->payload.userStats->from_client->lost = target->cryptState.uiLost;
747 sendmsg->payload.userStats->from_client->has_resync = true;
748 sendmsg->payload.userStats->from_client->resync = target->cryptState.uiResync;
750 sendmsg->payload.userStats->from_server->has_good = true;
751 sendmsg->payload.userStats->from_server->good = target->cryptState.uiRemoteGood;
752 sendmsg->payload.userStats->from_server->has_late = true;
753 sendmsg->payload.userStats->from_server->late = target->cryptState.uiRemoteLate;
754 sendmsg->payload.userStats->from_server->has_lost = true;
755 sendmsg->payload.userStats->from_server->lost = target->cryptState.uiRemoteLost;
756 sendmsg->payload.userStats->from_server->has_resync = true;
757 sendmsg->payload.userStats->from_server->resync = target->cryptState.uiRemoteResync;
759 sendmsg->payload.userStats->has_udp_packets = true;
760 sendmsg->payload.userStats->udp_packets = target->UDPPackets;
761 sendmsg->payload.userStats->has_udp_ping_avg = true;
762 sendmsg->payload.userStats->udp_ping_avg = target->UDPPingAvg;
763 sendmsg->payload.userStats->has_udp_ping_var = true;
764 sendmsg->payload.userStats->udp_ping_var = target->UDPPingVar;
766 sendmsg->payload.userStats->has_tcp_ping_avg = true;
767 sendmsg->payload.userStats->tcp_ping_avg = target->TCPPingAvg;
768 sendmsg->payload.userStats->has_tcp_ping_var = true;
769 sendmsg->payload.userStats->tcp_ping_var = target->TCPPingVar;
770 sendmsg->payload.userStats->has_tcp_packets = true;
771 sendmsg->payload.userStats->tcp_packets = target->TCPPackets;
775 sendmsg->payload.userStats->version->has_version = true;
776 sendmsg->payload.userStats->version->version = target->version;
777 sendmsg->payload.userStats->version->release = strdup(target->release);
778 sendmsg->payload.userStats->version->os = strdup(target->os);
779 sendmsg->payload.userStats->version->os_version = strdup(target->os_version);
781 sendmsg->payload.userStats->n_celt_versions = target->codec_count;
782 sendmsg->payload.userStats->celt_versions = malloc(sizeof(int32_t) * target->codec_count);
783 if (!sendmsg->payload.userStats->celt_versions)
784 Log_fatal("Out of memory");
786 while (Client_codec_iterate(target, &codec_itr) != NULL)
787 sendmsg->payload.userStats->celt_versions[i++] = codec_itr->codec;
790 sendmsg->payload.userStats->has_address = true;
791 sendmsg->payload.userStats->address.data = malloc(sizeof(uint8_t) * 16);
792 if (!sendmsg->payload.userStats->address.data)
793 Log_fatal("Out of memory");
794 memset(sendmsg->payload.userStats->address.data, 0, 16);
795 /* ipv4 representation as ipv6 address. Supposedly correct. */
796 memcpy(&sendmsg->payload.userStats->address.data[12], &target->remote_tcp.sin_addr, 4);
797 sendmsg->payload.userStats->address.len = 16;
800 sendmsg->payload.userStats->has_bandwidth = true;
801 sendmsg->payload.userStats->bandwidth = target->availableBandwidth;
804 sendmsg->payload.userStats->has_onlinesecs = true;
805 sendmsg->payload.userStats->onlinesecs = Timer_elapsed(&target->connectTime) / 1000000LL;
807 sendmsg->payload.userStats->has_idlesecs = true;
808 sendmsg->payload.userStats->idlesecs = Timer_elapsed(&target->idleTime) / 1000000LL;
809 Client_send_message(client, sendmsg);
814 /* Only admin can issue this */
815 if (!client->isAdmin) {
816 sendPermissionDenied(client, "Permission denied");
819 while (Client_iterate(&target) != NULL) {
820 if (target->sessionId == msg->payload.userRemove->session)
823 if (target == NULL) {
824 Log_warn("Client with sessionId %d not found", msg->payload.userRemove->session);
827 msg->payload.userRemove->session = target->sessionId;
828 msg->payload.userRemove->has_actor = true;
829 msg->payload.userRemove->actor = client->sessionId;
831 if (msg->payload.userRemove->has_ban && msg->payload.userRemove->ban) {
832 Ban_UserBan(target, msg->payload.userRemove->reason);
834 Log_info("User kicked");
839 Client_send_message_except(NULL, msg);
840 Client_close(target);
843 /* Permission denied for all these messages. Not implemented. */
846 case ContextActionAdd:
851 sendPermissionDenied(client, "Not supported by uMurmur");
855 Log_warn("Message %d not handled", msg->messageType);
864 Client_close(client);