1 /* Copyright (C) 2009-2012, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2012, 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 if (!getBoolConf(ALLOW_TEXTMESSAGE))
517 msg->payload.textMessage->has_actor = true;
518 msg->payload.textMessage->actor = client->sessionId;
520 /* XXX - HTML is allowed and can't be turned off */
521 if (msg->payload.textMessage->n_tree_id > 0) {
522 sendPermissionDenied(client, "Tree message not supported");
526 if (msg->payload.textMessage->n_channel_id > 0) { /* To channel */
529 for (i = 0; i < msg->payload.textMessage->n_channel_id; i++) {
532 Chan_iterate(&ch_itr);
533 } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage->channel_id[i]);
534 if (ch_itr != NULL) {
536 list_iterate(itr, &ch_itr->clients) {
538 c = list_get_entry(itr, client_t, chan_node);
539 if (c != client && !c->deaf) {
541 Client_send_message(c, msg);
542 Log_debug("Text message to session ID %d", c->sessionId);
548 if (msg->payload.textMessage->n_session > 0) { /* To user */
551 for (i = 0; i < msg->payload.textMessage->n_session; i++) {
553 while (Client_iterate(&itr) != NULL) {
556 if (itr->sessionId == msg->payload.textMessage->session[i]) {
559 Client_send_message(itr, msg);
560 Log_debug("Text message to session ID %d", itr->sessionId);
566 Log_warn("TextMessage: Session ID %d not found", msg->payload.textMessage->session[i]);
573 int i, j, count, targetId = msg->payload.voiceTarget->id;
574 struct _MumbleProto__VoiceTarget__Target *target;
576 if (!targetId || targetId >= 0x1f)
578 Voicetarget_add_id(client, targetId);
579 count = msg->payload.voiceTarget->n_targets;
582 for (i = 0; i < count; i++) {
583 target = msg->payload.voiceTarget->targets[i];
584 for (j = 0; j < target->n_session; j++)
585 Voicetarget_add_session(client, targetId, target->session[j]);
586 if (target->has_channel_id) {
587 bool_t linked = false, children = false;
588 if (target->has_links)
589 linked = target->links;
590 if (target->has_children)
591 children = target->children;
592 Voicetarget_add_channel(client, targetId, target->channel_id, linked, children);
598 Log_debug("Version message received");
599 if (msg->payload.version->has_version) {
600 client->version = msg->payload.version->version;
601 Log_debug("Client version 0x%x", client->version);
603 if (msg->payload.version->release) {
604 if (client->release) free(client->release);
605 client->release = strdup(msg->payload.version->release);
606 Log_debug("Client release %s", client->release);
608 if (msg->payload.version->os) {
609 if (client->os) free(client->os);
610 client->os = strdup(msg->payload.version->os);
611 Log_debug("Client OS %s", client->os);
613 if (msg->payload.version->os_version) {
614 if (client->os_version) free(client->os_version);
615 client->os_version = strdup(msg->payload.version->os_version);
616 Log_debug("Client OS version %s", client->os_version);
619 case PermissionQuery:
620 Msg_inc_ref(msg); /* Re-use message */
621 msg->payload.permissionQuery->has_permissions = true;
624 msg->payload.permissionQuery->permissions = PERM_ADMIN;
626 msg->payload.permissionQuery->permissions = PERM_DEFAULT;
628 if (!getBoolConf(ALLOW_TEXTMESSAGE))
629 msg->payload.permissionQuery->permissions &= ~PERM_TEXTMESSAGE;
631 Client_send_message(client, msg);
634 client->bUDP = false;
635 Client_voiceMsg(client, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
639 channel_t *ch_itr, *parent, *newchan;
641 /* Don't allow any changes to existing channels */
642 if (msg->payload.channelState->has_channel_id) {
643 sendPermissionDenied(client, "Not supported by uMurmur");
646 /* Must have parent */
647 if (!msg->payload.channelState->has_parent) {
648 sendPermissionDenied(client, "Not supported by uMurmur");
652 if (msg->payload.channelState->name == NULL) {
653 sendPermissionDenied(client, "Not supported by uMurmur");
656 /* Must be temporary channel */
657 if (msg->payload.channelState->temporary != true) {
658 sendPermissionDenied(client, "Only temporary channels are supported by uMurmur");
661 /* Check channel name is OK */
662 if (strlen(msg->payload.channelState->name) > MAX_TEXT) {
663 sendPermissionDenied(client, "Channel name too long");
667 parent = Chan_fromId(msg->payload.channelState->parent);
671 while (Chan_iterate_siblings(parent, &ch_itr) != NULL) {
672 if (strcmp(ch_itr->name, msg->payload.channelState->name) == 0) {
673 sendPermissionDenied(client, "Channel already exists");
680 /* Disallow temporary channels as siblings to temporary channels */
681 if (parent->temporary) {
682 sendPermissionDenied(client, "Parent channel is temporary channel");
686 /* XXX - Murmur looks for "\\w" and sends perm denied if not found.
687 * I don't know why so I don't do that here...
690 /* Create the channel */
691 newchan = Chan_createChannel(msg->payload.channelState->name,
692 msg->payload.channelState->description);
693 newchan->temporary = true;
694 Chan_addChannel(parent, newchan);
695 msg->payload.channelState->has_channel_id = true;
696 msg->payload.channelState->channel_id = newchan->id;
698 Client_send_message_except(NULL, msg);
700 /* Join the creating user */
701 sendmsg = Msg_create(UserState);
702 sendmsg->payload.userState->has_session = true;
703 sendmsg->payload.userState->session = client->sessionId;
704 sendmsg->payload.userState->has_channel_id = true;
705 sendmsg->payload.userState->channel_id = newchan->id;
706 Client_send_message_except(NULL, sendmsg);
708 leave_id = Chan_userJoin(newchan, client);
710 Log_debug("Removing channel ID %d", leave_id);
711 sendmsg = Msg_create(ChannelRemove);
712 sendmsg->payload.channelRemove->channel_id = leave_id;
713 Client_send_message_except(NULL, sendmsg);
720 client_t *target = NULL;
721 codec_t *codec_itr = NULL;
723 bool_t details = true;
725 if (msg->payload.userStats->has_stats_only)
726 details = !msg->payload.userStats->stats_only;
728 if (!msg->payload.userStats->has_session)
729 sendPermissionDenied(client, "Not supported by uMurmur");
730 while (Client_iterate(&target) != NULL) {
731 if (!IS_AUTH(target))
733 if (target->sessionId == msg->payload.userStats->session)
736 if (!target) /* Not found */
740 * Differences from Murmur:
741 * o Ignoring certificates intentionally
742 * o Ignoring channel local determining
745 sendmsg = Msg_create(UserStats);
746 sendmsg->payload.userStats->session = msg->payload.userStats->session;
747 sendmsg->payload.userStats->from_client->has_good = true;
748 sendmsg->payload.userStats->from_client->good = target->cryptState.uiGood;
749 sendmsg->payload.userStats->from_client->has_late = true;
750 sendmsg->payload.userStats->from_client->late = target->cryptState.uiLate;
751 sendmsg->payload.userStats->from_client->has_lost = true;
752 sendmsg->payload.userStats->from_client->lost = target->cryptState.uiLost;
753 sendmsg->payload.userStats->from_client->has_resync = true;
754 sendmsg->payload.userStats->from_client->resync = target->cryptState.uiResync;
756 sendmsg->payload.userStats->from_server->has_good = true;
757 sendmsg->payload.userStats->from_server->good = target->cryptState.uiRemoteGood;
758 sendmsg->payload.userStats->from_server->has_late = true;
759 sendmsg->payload.userStats->from_server->late = target->cryptState.uiRemoteLate;
760 sendmsg->payload.userStats->from_server->has_lost = true;
761 sendmsg->payload.userStats->from_server->lost = target->cryptState.uiRemoteLost;
762 sendmsg->payload.userStats->from_server->has_resync = true;
763 sendmsg->payload.userStats->from_server->resync = target->cryptState.uiRemoteResync;
765 sendmsg->payload.userStats->has_udp_packets = true;
766 sendmsg->payload.userStats->udp_packets = target->UDPPackets;
767 sendmsg->payload.userStats->has_udp_ping_avg = true;
768 sendmsg->payload.userStats->udp_ping_avg = target->UDPPingAvg;
769 sendmsg->payload.userStats->has_udp_ping_var = true;
770 sendmsg->payload.userStats->udp_ping_var = target->UDPPingVar;
772 sendmsg->payload.userStats->has_tcp_ping_avg = true;
773 sendmsg->payload.userStats->tcp_ping_avg = target->TCPPingAvg;
774 sendmsg->payload.userStats->has_tcp_ping_var = true;
775 sendmsg->payload.userStats->tcp_ping_var = target->TCPPingVar;
776 sendmsg->payload.userStats->has_tcp_packets = true;
777 sendmsg->payload.userStats->tcp_packets = target->TCPPackets;
781 sendmsg->payload.userStats->version->has_version = true;
782 sendmsg->payload.userStats->version->version = target->version;
783 sendmsg->payload.userStats->version->release = strdup(target->release);
784 sendmsg->payload.userStats->version->os = strdup(target->os);
785 sendmsg->payload.userStats->version->os_version = strdup(target->os_version);
787 sendmsg->payload.userStats->n_celt_versions = target->codec_count;
788 sendmsg->payload.userStats->celt_versions = malloc(sizeof(int32_t) * target->codec_count);
789 if (!sendmsg->payload.userStats->celt_versions)
790 Log_fatal("Out of memory");
792 while (Client_codec_iterate(target, &codec_itr) != NULL)
793 sendmsg->payload.userStats->celt_versions[i++] = codec_itr->codec;
796 sendmsg->payload.userStats->has_address = true;
797 sendmsg->payload.userStats->address.data = malloc(sizeof(uint8_t) * 16);
798 if (!sendmsg->payload.userStats->address.data)
799 Log_fatal("Out of memory");
800 memset(sendmsg->payload.userStats->address.data, 0, 16);
801 /* ipv4 representation as ipv6 address. Supposedly correct. */
802 memcpy(&sendmsg->payload.userStats->address.data[12], &target->remote_tcp.sin_addr, 4);
803 sendmsg->payload.userStats->address.len = 16;
806 sendmsg->payload.userStats->has_bandwidth = true;
807 sendmsg->payload.userStats->bandwidth = target->availableBandwidth;
810 sendmsg->payload.userStats->has_onlinesecs = true;
811 sendmsg->payload.userStats->onlinesecs = Timer_elapsed(&target->connectTime) / 1000000LL;
813 sendmsg->payload.userStats->has_idlesecs = true;
814 sendmsg->payload.userStats->idlesecs = Timer_elapsed(&target->idleTime) / 1000000LL;
815 Client_send_message(client, sendmsg);
820 /* Only admin can issue this */
821 if (!client->isAdmin) {
822 sendPermissionDenied(client, "Permission denied");
825 while (Client_iterate(&target) != NULL) {
826 if (target->sessionId == msg->payload.userRemove->session)
829 if (target == NULL) {
830 Log_warn("Client with sessionId %d not found", msg->payload.userRemove->session);
833 msg->payload.userRemove->session = target->sessionId;
834 msg->payload.userRemove->has_actor = true;
835 msg->payload.userRemove->actor = client->sessionId;
837 if (msg->payload.userRemove->has_ban && msg->payload.userRemove->ban) {
838 Ban_UserBan(target, msg->payload.userRemove->reason);
840 Log_info("User kicked");
845 Client_send_message_except(NULL, msg);
846 Client_close(target);
849 /* Permission denied for all these messages. Not implemented. */
852 case ContextActionAdd:
857 sendPermissionDenied(client, "Not supported by uMurmur");
861 Log_warn("Message %d not handled", msg->messageType);
870 Client_close(client);