Add support for UserStats message.
[umurmur.git] / src / messagehandler.c
1 /* Copyright (C) 2009-2010, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2010, Thorvald Natvig <thorvald@natvig.com>
3
4    All rights reserved.
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9
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.
18
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.
30 */
31 #include <string.h>
32 #include <stdlib.h>
33
34 #include "log.h"
35 #include "list.h"
36 #include "client.h"
37 #include "messages.h"
38 #include "messagehandler.h"
39 #include "crypt.h"
40 #include "channel.h"
41 #include "conf.h"
42 #include "voicetarget.h"
43
44 #define MAX_TEXT 512
45
46 extern channel_t *defaultChan;
47 extern int iCodecAlpha, iCodecBeta;
48 extern bool_t bPreferAlpha;
49
50 static void sendServerReject(client_t *client, const char *reason, MumbleProto__Reject__RejectType type)
51 {
52         message_t *msg = Msg_create(Reject);
53         msg->payload.reject->reason = strdup(reason);
54         msg->payload.reject->type = type;
55         msg->payload.reject->has_type = true;
56         Client_send_message(client, msg);
57         
58         Log_info_client(client, "Server reject reason: %s", reason);
59 }
60
61 static void sendPermissionDenied(client_t *client, const char *reason)
62 {
63         message_t *msg = Msg_create(PermissionDenied);
64         msg->payload.permissionDenied->has_type = true;
65         msg->payload.permissionDenied->type = MUMBLE_PROTO__PERMISSION_DENIED__DENY_TYPE__Text;
66         msg->payload.permissionDenied->reason = strdup(reason);
67         Client_send_message(client, msg);
68 }
69
70 void Mh_handle_message(client_t *client, message_t *msg)
71 {
72         message_t *sendmsg = NULL;
73         channel_t *ch_itr = NULL;
74         client_t *client_itr;
75
76         if (!client->authenticated && !(msg->messageType == Authenticate ||
77                                                                         msg->messageType == Version)) {
78                 goto out;
79         }
80         
81         switch (msg->messageType) {
82         case UDPTunnel:
83         case Ping:
84         case CryptSetup:
85         case VoiceTarget:
86         case UserStats:
87         case PermissionQuery:
88                 break;
89         default:
90                 Timer_restart(&client->idleTime);
91         }
92         
93         switch (msg->messageType) {
94         case Authenticate:
95                 Log_debug("Authenticate message received");
96                 
97                 if (IS_AUTH(client) || !msg->payload.authenticate->username) {
98                         /* Authenticate message might be sent when a token is set by the user.*/
99                         if (msg->payload.authenticate->n_tokens > 0) {
100                                 Log_debug("Tokens in auth message from %s", client->username);
101                         }
102                         break;
103                 }
104                 
105                 client->authenticated = true;
106                 
107                 client_itr = NULL;
108                 while (Client_iterate(&client_itr) != NULL) {
109                         if (!IS_AUTH(client_itr))
110                                 continue;
111                         if (client_itr->username && strncmp(client_itr->username, msg->payload.authenticate->username, MAX_TEXT) == 0) {
112                                 char buf[64];
113                                 sprintf(buf, "Username already in use");
114                                 Log_debug("Username already in use");
115                                 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__UsernameInUse);
116                                 goto disconnect;
117                         }                               
118                 }
119                 if (strlen(getStrConf(PASSPHRASE)) > 0) {
120                         if (!msg->payload.authenticate->password ||
121                                 (msg->payload.authenticate->password &&
122                                  strncmp(getStrConf(PASSPHRASE), msg->payload.authenticate->password, MAX_TEXT) != 0)) {
123                                 char buf[64];
124                                 sprintf(buf, "Wrong server password");
125                                 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__WrongServerPW);
126                                 Log_debug("Wrong server password: '%s'", msg->payload.authenticate->password != NULL ?
127                                                   msg->payload.authenticate->password : "(null)");
128                                 goto disconnect;
129                         }
130                 }                               
131                 if (strlen(msg->payload.authenticate->username) == 0 ||
132                         strlen(msg->payload.authenticate->username) >= MAX_TEXT) { /* XXX - other invalid names? */
133                         char buf[64];
134                         sprintf(buf, "Invalid username");
135                         Log_debug("Invalid username");
136                         sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__InvalidUsername);
137                         goto disconnect;
138                 }                               
139
140                 if (Client_count() >= getIntConf(MAX_CLIENTS)) {
141                         char buf[64];
142                         sprintf(buf, "Server is full (max %d users)", getIntConf(MAX_CLIENTS));
143                         sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__ServerFull);
144                         goto disconnect;
145                 }
146                 
147                 /* Name & password */
148                 client->username = strdup(msg->payload.authenticate->username);                         
149                 
150                 /* Setup UDP encryption */
151                 CryptState_init(&client->cryptState);
152                 CryptState_genKey(&client->cryptState);
153                 sendmsg = Msg_create(CryptSetup);
154                 sendmsg->payload.cryptSetup->has_key = true;
155                 sendmsg->payload.cryptSetup->key.data = client->cryptState.raw_key;
156                 sendmsg->payload.cryptSetup->key.len = AES_BLOCK_SIZE;
157                 sendmsg->payload.cryptSetup->has_server_nonce = true;
158                 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.encrypt_iv;
159                 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
160                 sendmsg->payload.cryptSetup->has_client_nonce = true;
161                 sendmsg->payload.cryptSetup->client_nonce.data = client->cryptState.decrypt_iv;
162                 sendmsg->payload.cryptSetup->client_nonce.len = AES_BLOCK_SIZE;
163                 Client_send_message(client, sendmsg);
164
165                 /* Channel stuff */
166                 Chan_userJoin(defaultChan, client); /* Join default channel */
167
168                 /* Codec version */             
169                 Log_debug("Client %d has %d CELT codecs", client->sessionId,
170                                   msg->payload.authenticate->n_celt_versions);
171                 if (msg->payload.authenticate->n_celt_versions > 0) {
172                         int i;
173                         codec_t *codec_itr;
174                         client->codec_count = msg->payload.authenticate->n_celt_versions;
175                         
176                         for (i = 0; i < client->codec_count; i++)
177                         Client_codec_add(client, msg->payload.authenticate->celt_versions[i]);
178                         codec_itr = NULL;
179                         while (Client_codec_iterate(client, &codec_itr) != NULL)
180                                 Log_debug("Client %d CELT codec ver 0x%x", client->sessionId, codec_itr->codec);
181                                 
182                 } else {
183                         Client_codec_add(client, (int32_t)0x8000000a);
184                         client->codec_count = 1;
185                 }
186                 
187                 recheckCodecVersions();
188                 
189                 sendmsg = Msg_create(CodecVersion);
190                 sendmsg->payload.codecVersion->alpha = iCodecAlpha;
191                 sendmsg->payload.codecVersion->beta = iCodecBeta;
192                 sendmsg->payload.codecVersion->prefer_alpha = bPreferAlpha;
193                 Client_send_message(client, sendmsg);
194                 
195                 /* Iterate channels and send channel info */
196                 ch_itr = NULL;
197                 while (Chan_iterate(&ch_itr) != NULL) {
198                         sendmsg = Msg_create(ChannelState);
199                         sendmsg->payload.channelState->has_channel_id = true;
200                         sendmsg->payload.channelState->channel_id = ch_itr->id;
201                         if (ch_itr->id != 0) {
202                                 sendmsg->payload.channelState->has_parent = true;
203                                 sendmsg->payload.channelState->parent = ch_itr->parent->id;
204                         }
205                         sendmsg->payload.channelState->name = strdup(ch_itr->name);
206                         if (ch_itr->desc)
207                                 sendmsg->payload.channelState->description = strdup(ch_itr->desc);
208                         Log_debug("Send channel info: %s", sendmsg->payload.channelState->name);
209                         Client_send_message(client, sendmsg);                   
210                 }
211
212                 /* Iterate channels and send channel links info */
213                 ch_itr = NULL;
214                 while (Chan_iterate(&ch_itr) != NULL) {
215                         if (ch_itr->linkcount > 0) { /* Has links */
216                                 uint32_t *links;
217                                 int i = 0;
218                                 struct dlist *itr;
219                                 
220                                 sendmsg = Msg_create(ChannelState);
221                                 sendmsg->payload.channelState->has_channel_id = true;
222                                 sendmsg->payload.channelState->channel_id = ch_itr->id;
223                                 sendmsg->payload.channelState->n_links = ch_itr->linkcount;
224                                 
225                                 links = (uint32_t *)malloc(ch_itr->linkcount * sizeof(uint32_t));
226                                 list_iterate(itr, &ch_itr->channel_links) { /* Iterate links */
227                                         channel_t *ch;
228                                         ch = list_get_entry(itr, channel_t, link_node);
229                                         links[i++] = ch->id;
230                                 }
231                                 sendmsg->payload.channelState->links = links;
232                                 Client_send_message(client, sendmsg);
233                         }
234                 }
235                 
236                 /* Send user state for connecting user to other users */
237                 sendmsg = Msg_create(UserState);
238                 sendmsg->payload.userState->has_session = true;
239                 sendmsg->payload.userState->session = client->sessionId;
240                 sendmsg->payload.userState->name = strdup(client->username);
241                 sendmsg->payload.userState->has_channel_id = true;
242                 sendmsg->payload.userState->channel_id = ((channel_t *)client->channel)->id;
243                 
244                 Client_send_message_except(client, sendmsg);
245
246                 client_itr = NULL;
247                 while (Client_iterate(&client_itr) != NULL) {
248                         if (!IS_AUTH(client_itr))
249                                 continue;
250                         sendmsg = Msg_create(UserState);
251                         sendmsg->payload.userState->has_session = true;
252                         sendmsg->payload.userState->session = client_itr->sessionId;
253                         sendmsg->payload.userState->name = strdup(client_itr->username);
254                         sendmsg->payload.userState->has_channel_id = true;
255                         sendmsg->payload.userState->channel_id = ((channel_t *)client_itr->channel)->id;
256
257                         /* Only self_mute/deaf supported */
258                         if (client_itr->deaf) {
259                                 sendmsg->payload.userState->has_self_deaf = true;
260                                 sendmsg->payload.userState->self_deaf = true;
261                         }
262                         if (client_itr->mute) {
263                                 sendmsg->payload.userState->has_self_mute = true;
264                                 sendmsg->payload.userState->self_mute = true;
265                         }
266                         Client_send_message(client, sendmsg);
267                 }
268
269                 /* Sync message */
270                 sendmsg = Msg_create(ServerSync);
271                 sendmsg->payload.serverSync->has_session = true;
272                 sendmsg->payload.serverSync->session = client->sessionId;
273                 sendmsg->payload.serverSync->welcome_text = strdup(getStrConf(WELCOMETEXT));
274                 sendmsg->payload.serverSync->has_max_bandwidth = true;
275                 sendmsg->payload.serverSync->max_bandwidth = getIntConf(MAX_BANDWIDTH);
276                 Client_send_message(client, sendmsg);
277
278                 /* Server config message */
279                 sendmsg = Msg_create(ServerConfig);             
280                 sendmsg->payload.serverConfig->has_allow_html = true;
281                 sendmsg->payload.serverConfig->allow_html = true; /* Support this? */
282                 sendmsg->payload.serverConfig->has_message_length = true;
283                 sendmsg->payload.serverConfig->message_length = MAX_TEXT; /* Hardcoded */
284                 sendmsg->payload.serverConfig->has_image_message_length = true;
285                 sendmsg->payload.serverConfig->image_message_length = 0; /* XXX */
286                 Client_send_message(client, sendmsg);
287
288                 Log_info_client(client, "User %s authenticated", client->username);
289                 break;
290                 
291         case Ping:
292                 if (msg->payload.ping->has_good)
293                         client->cryptState.uiRemoteGood = msg->payload.ping->good;
294                 if (msg->payload.ping->has_late)
295                         client->cryptState.uiRemoteLate = msg->payload.ping->late;
296                 if (msg->payload.ping->has_lost)
297                         client->cryptState.uiRemoteLost = msg->payload.ping->lost;
298                 if (msg->payload.ping->has_resync)
299                         client->cryptState.uiRemoteResync = msg->payload.ping->resync;
300
301                 Log_debug("Ping <-: %d %d %d %d",
302                                   client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate,
303                                   client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync
304                         );
305                 
306                 client->UDPPingAvg = msg->payload.ping->udp_ping_avg;
307                 client->UDPPingVar = msg->payload.ping->udp_ping_var;
308                 client->TCPPingAvg = msg->payload.ping->tcp_ping_avg;
309                 client->TCPPingVar = msg->payload.ping->tcp_ping_var;
310                 client->UDPPackets = msg->payload.ping->udp_packets;
311                 client->TCPPackets = msg->payload.ping->tcp_packets;
312                 
313                 sendmsg = Msg_create(Ping);
314
315                 sendmsg->payload.ping->timestamp = msg->payload.ping->timestamp;
316                 sendmsg->payload.ping->has_timestamp = true;
317                 sendmsg->payload.ping->good = client->cryptState.uiGood;
318                 sendmsg->payload.ping->has_good = true;
319                 sendmsg->payload.ping->late = client->cryptState.uiLate;
320                 sendmsg->payload.ping->has_late = true;
321                 sendmsg->payload.ping->lost = client->cryptState.uiLost;
322                 sendmsg->payload.ping->has_lost = true;
323                 sendmsg->payload.ping->resync = client->cryptState.uiResync;
324                 sendmsg->payload.ping->has_resync = true;
325
326                 Client_send_message(client, sendmsg);
327                 Log_debug("Ping ->: %d %d %d %d",
328                                   client->cryptState.uiGood, client->cryptState.uiLate,
329                                   client->cryptState.uiLost, client->cryptState.uiResync);
330
331                 break;
332         case CryptSetup:
333                 Log_debug("Voice channel crypt resync requested");
334                 if (!msg->payload.cryptSetup->has_client_nonce) {
335                         sendmsg = Msg_create(CryptSetup);
336                         sendmsg->payload.cryptSetup->has_server_nonce = true;
337                         sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.decrypt_iv;
338                         sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
339                         Client_send_message(client, sendmsg);
340                 } else {
341                         memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSetup->client_nonce.data, AES_BLOCK_SIZE);
342                         client->cryptState.uiResync++;
343                 }
344                 break;
345         case UserState:
346                 /* Only allow state changes for for the self user */
347                 if (msg->payload.userState->has_session &&
348                         msg->payload.userState->session != client->sessionId) {
349                         sendPermissionDenied(client, "Permission denied");
350                         break;
351                 }
352                 if (msg->payload.userState->has_user_id || msg->payload.userState->has_mute ||
353                         msg->payload.userState->has_deaf || msg->payload.userState->has_suppress ||
354                         msg->payload.userState->has_texture) {
355                         
356                         sendPermissionDenied(client, "Not supported by uMurmur");
357                         break;
358                 }
359                 
360                 msg->payload.userState->has_session = true;
361                 msg->payload.userState->session = client->sessionId;
362                 msg->payload.userState->has_actor = true;
363                 msg->payload.userState->actor = client->sessionId;
364
365                 if (msg->payload.userState->has_self_deaf) {
366                         client->deaf = msg->payload.userState->self_deaf;
367                 }
368                 if (msg->payload.userState->has_self_mute) {
369                         client->mute = msg->payload.userState->self_mute;
370                         if (!client->mute) {
371                                 msg->payload.userState->has_self_deaf = true;
372                                 msg->payload.userState->self_deaf = false;
373                                 client->deaf = false;
374                         }
375                 }
376                 if (msg->payload.userState->has_channel_id) {
377                         int leave_id;
378                         if (!Chan_userJoin_id_test(msg->payload.userState->channel_id))
379                                 break;
380                         leave_id = Chan_userJoin_id(msg->payload.userState->channel_id, client);
381                         if (leave_id > 0) {
382                                 Log_debug("Removing channel ID %d", leave_id);
383                                 sendmsg = Msg_create(ChannelRemove);
384                                 sendmsg->payload.channelRemove->channel_id = leave_id;
385                         }
386                 }
387                 if (msg->payload.userState->has_plugin_context) {
388                         if (client->context)
389                                 free(client->context);
390                         client->context = malloc(msg->payload.userState->plugin_context.len);
391                         if (client->context == NULL)
392                                 Log_fatal("Out of memory");
393                         memcpy(client->context, msg->payload.userState->plugin_context.data,
394                                    msg->payload.userState->plugin_context.len);
395                         
396                         break; /* Don't inform other users about this state */
397                 }
398                 
399                 /* Re-use message */
400                 Msg_inc_ref(msg);
401                                 
402                 Client_send_message_except(NULL, msg);
403
404                 /* Need to send remove channel message _after_ UserState message */
405                 if (sendmsg != NULL)
406                         Client_send_message_except(NULL, sendmsg);
407                 break;
408                 
409         case TextMessage:
410                 msg->payload.textMessage->has_actor = true;
411                 msg->payload.textMessage->actor = client->sessionId;
412
413                 /* XXX - HTML is allowed and can't be turned off */
414                 if (msg->payload.textMessage->n_tree_id > 0) {
415                         sendPermissionDenied(client, "Tree message not supported");
416                         break;
417                 }
418                         
419                 if (msg->payload.textMessage->n_channel_id > 0) { /* To channel */
420                         int i;
421                         channel_t *ch_itr;
422                         for (i = 0; i < msg->payload.textMessage->n_channel_id; i++) {
423                                 ch_itr = NULL;
424                                 do {
425                                         Chan_iterate(&ch_itr);
426                                 } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage->channel_id[i]);
427                                 if (ch_itr != NULL) {
428                                         struct dlist *itr;
429                                         list_iterate(itr, &ch_itr->clients) {
430                                                 client_t *c;
431                                                 c = list_get_entry(itr, client_t, chan_node);
432                                                 if (c != client && !c->deaf) {
433                                                         Msg_inc_ref(msg);
434                                                         Client_send_message(c, msg);
435                                                         Log_debug("Text message to session ID %d", c->sessionId);
436                                                 }
437                                         }
438                                 }
439                         } /* for */
440                 }
441                 if (msg->payload.textMessage->n_session > 0) { /* To user */
442                         int i;
443                         client_t *itr;
444                         for (i = 0; i < msg->payload.textMessage->n_session; i++) {
445                                 itr = NULL;
446                                 while (Client_iterate(&itr) != NULL) {
447                                         if (!IS_AUTH(itr))
448                                                 continue;
449                                         if (itr->sessionId == msg->payload.textMessage->session[i]) {
450                                                 if (!itr->deaf) {
451                                                         Msg_inc_ref(msg);
452                                                         Client_send_message(itr, msg);
453                                                         Log_debug("Text message to session ID %d", itr->sessionId);
454                                                 }
455                                                 break;
456                                         }
457                                 }
458                                 if (itr == NULL)
459                                         Log_warn("TextMessage: Session ID %d not found", msg->payload.textMessage->session[i]);
460                         } /* for */
461                 }
462                 break;
463
464         case VoiceTarget:
465         {
466                 int i, j, count, targetId = msg->payload.voiceTarget->id;
467                 struct _MumbleProto__VoiceTarget__Target *target;
468
469                 if (!targetId || targetId >= 0x1f)
470                         break;
471                 Voicetarget_add_id(client, targetId);
472                 count = msg->payload.voiceTarget->n_targets;
473                 if (!count)
474                         break;
475                 for (i = 0; i < count; i++) {
476                         target = msg->payload.voiceTarget->targets[i];
477                         for (j = 0; j < target->n_session; j++)
478                                 Voicetarget_add_session(client, targetId, target->session[j]);
479                         if (target->has_channel_id) {
480                                 bool_t linked = false, children = false;
481                                 if (target->has_links)
482                                         linked = target->links;
483                                 if (target->has_children)
484                                         children = target->children;
485                                 Voicetarget_add_channel(client, targetId, target->channel_id, linked, children);
486                         }
487                 }
488                 break;
489         }
490         case Version:
491                 Log_debug("Version message received");
492                 if (msg->payload.version->has_version) {
493                         client->version = msg->payload.version->version;
494                         Log_debug("Client version 0x%x", client->version);
495                 }
496                 if (msg->payload.version->release) {
497                         if (client->release) free(client->release);
498                         client->release = strdup(msg->payload.version->release);
499                         Log_debug("Client release %s", client->release);
500                 }
501                 if (msg->payload.version->os) {
502                         if (client->os) free(client->os);                       
503                         client->os = strdup(msg->payload.version->os);
504                         Log_debug("Client OS %s", client->os);
505                 }
506                 if (msg->payload.version->os_version) {
507                         if (client->os_version) free(client->os_version);                       
508                         client->os_version = strdup(msg->payload.version->os_version);
509                         Log_debug("Client OS version %s", client->os_version);
510                 }
511                 break;
512         case PermissionQuery:
513                 Msg_inc_ref(msg); /* Re-use message */
514                 msg->payload.permissionQuery->has_permissions = true;
515                 msg->payload.permissionQuery->permissions = PERM_DEFAULT;
516                 
517                 Client_send_message(client, msg);
518                 break;
519         case UDPTunnel:
520                 client->bUDP = false;
521                 Client_voiceMsg(client, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
522             break;
523         case ChannelState:
524         {
525                 channel_t *ch_itr, *parent, *newchan;
526                 int leave_id;           
527                 /* Don't allow any changes to existing channels */
528                 if (msg->payload.channelState->has_channel_id) {
529                         sendPermissionDenied(client, "Not supported by uMurmur");
530                         break;
531                 }
532                 /* Must have parent */
533                 if (!msg->payload.channelState->has_parent) {
534                         sendPermissionDenied(client, "Not supported by uMurmur");
535                         break;
536                 }
537                 /* Must have name */
538                 if (msg->payload.channelState->name == NULL) {
539                         sendPermissionDenied(client, "Not supported by uMurmur");
540                         break;
541                 }
542                 /* Must be temporary channel */
543                 if (msg->payload.channelState->temporary != true) {
544                         sendPermissionDenied(client, "Only temporary channels are supported by uMurmur");
545                         break;
546                 }
547                 /* Check channel name is OK */
548                 if (strlen(msg->payload.channelState->name) > MAX_TEXT) {
549                         sendPermissionDenied(client, "Channel name too long");
550                         break;
551                 }
552                         
553                 parent = Chan_fromId(msg->payload.channelState->parent);
554                 if (parent == NULL)
555                         break;
556                 ch_itr = NULL;
557                 while (Chan_iterate_siblings(parent, &ch_itr) != NULL) {
558                         if (strcmp(ch_itr->name, msg->payload.channelState->name) == 0) {
559                                 sendPermissionDenied(client, "Channel already exists");
560                                 break;
561                         }
562                 }
563                 if (ch_itr != NULL)
564                         break;
565                 
566                 /* Disallow temporary channels as siblings to temporary channels */
567                 if (parent->temporary) {
568                         sendPermissionDenied(client, "Parent channel is temporary channel");
569                         break;
570                 }
571                         
572                 /* XXX - Murmur looks for "\\w" and sends perm denied if not found.
573                  * I don't know why so I don't do that here...
574                  */
575
576                 /* Create the channel */
577                 newchan = Chan_createChannel(msg->payload.channelState->name,
578                                                                          msg->payload.channelState->description);
579                 newchan->temporary = true;
580                 Chan_addChannel(parent, newchan);
581                 msg->payload.channelState->has_channel_id = true;
582                 msg->payload.channelState->channel_id = newchan->id;
583                 Msg_inc_ref(msg);
584                 Client_send_message_except(NULL, msg);
585
586                 /* Join the creating user */
587                 sendmsg = Msg_create(UserState);
588                 sendmsg->payload.userState->has_session = true;
589                 sendmsg->payload.userState->session = client->sessionId;
590                 sendmsg->payload.userState->has_channel_id = true;
591                 sendmsg->payload.userState->channel_id = newchan->id;
592                 Client_send_message_except(NULL, sendmsg);
593                 
594                 leave_id = Chan_userJoin(newchan, client);
595                 if (leave_id > 0) {
596                         Log_debug("Removing channel ID %d", leave_id);
597                         sendmsg = Msg_create(ChannelRemove);
598                         sendmsg->payload.channelRemove->channel_id = leave_id;
599                         Client_send_message_except(NULL, sendmsg);
600                 }
601         }               
602         break;
603
604         case UserStats:
605         {
606                 client_t *target = NULL;
607                 codec_t *codec_itr = NULL;
608                 int i;
609                 bool_t details = true;
610                 
611                 if (msg->payload.userStats->has_stats_only)
612                         details = !msg->payload.userStats->stats_only;
613                 
614                 if (!msg->payload.userStats->has_session)
615                         sendPermissionDenied(client, "Not supported by uMurmur");
616                 while (Client_iterate(&target) != NULL) {
617                         if (!IS_AUTH(target))
618                                 continue;
619                         if (target->sessionId == msg->payload.userStats->session)
620                                 break;
621                 }
622                 if (!target) /* Not found */
623                         break;
624                 
625                 /*
626                  * Differences from Murmur:
627                  * o Ignoring certificates intentionally
628                  * o Ignoring channel local determining
629                  */
630                 
631                 sendmsg = Msg_create(UserStats);
632                 sendmsg->payload.userStats->session = msg->payload.userStats->session;
633                 sendmsg->payload.userStats->from_client->has_good = true;
634                 sendmsg->payload.userStats->from_client->good = target->cryptState.uiGood;
635                 sendmsg->payload.userStats->from_client->has_late = true;
636                 sendmsg->payload.userStats->from_client->late = target->cryptState.uiLate;
637                 sendmsg->payload.userStats->from_client->has_lost = true;
638                 sendmsg->payload.userStats->from_client->lost = target->cryptState.uiLost;
639                 sendmsg->payload.userStats->from_client->has_resync = true;
640                 sendmsg->payload.userStats->from_client->resync = target->cryptState.uiResync;
641                 
642                 sendmsg->payload.userStats->from_server->has_good = true;
643                 sendmsg->payload.userStats->from_server->good = target->cryptState.uiRemoteGood;
644                 sendmsg->payload.userStats->from_server->has_late = true;
645                 sendmsg->payload.userStats->from_server->late = target->cryptState.uiRemoteLate;
646                 sendmsg->payload.userStats->from_server->has_lost = true;
647                 sendmsg->payload.userStats->from_server->lost = target->cryptState.uiRemoteLost;
648                 sendmsg->payload.userStats->from_server->has_resync = true;
649                 sendmsg->payload.userStats->from_server->resync = target->cryptState.uiRemoteResync;
650
651                 sendmsg->payload.userStats->has_udp_packets = true;
652                 sendmsg->payload.userStats->udp_packets = target->UDPPackets;
653                 sendmsg->payload.userStats->has_udp_ping_avg = true;
654                 sendmsg->payload.userStats->udp_ping_avg = target->UDPPingAvg;
655                 sendmsg->payload.userStats->has_udp_ping_var = true;
656                 sendmsg->payload.userStats->udp_ping_var = target->UDPPingVar;
657                 
658                 sendmsg->payload.userStats->has_tcp_ping_avg = true;
659                 sendmsg->payload.userStats->tcp_ping_avg = target->TCPPingAvg;
660                 sendmsg->payload.userStats->has_tcp_ping_var = true;
661                 sendmsg->payload.userStats->tcp_ping_var = target->TCPPingVar;
662                 sendmsg->payload.userStats->has_tcp_packets = true;
663                 sendmsg->payload.userStats->tcp_packets = target->TCPPackets;
664                 
665                 if (details) {
666
667                         sendmsg->payload.userStats->version->has_version = true;
668                         sendmsg->payload.userStats->version->version = target->version;
669                         sendmsg->payload.userStats->version->release = strdup(target->release);
670                         sendmsg->payload.userStats->version->os = strdup(target->os);
671                         sendmsg->payload.userStats->version->os_version = strdup(target->os_version);
672                         
673                         sendmsg->payload.userStats->n_celt_versions = target->codec_count;
674                         sendmsg->payload.userStats->celt_versions = malloc(sizeof(int32_t) * target->codec_count);
675                         if (!sendmsg->payload.userStats->celt_versions)
676                                 Log_fatal("Out of memory");
677                         i = 0;
678                         while (Client_codec_iterate(target, &codec_itr) != NULL)
679                                 sendmsg->payload.userStats->celt_versions[i++] = codec_itr->codec;
680
681                         /* Address */
682                         sendmsg->payload.userStats->has_address = true;
683                         sendmsg->payload.userStats->address.data = malloc(sizeof(uint8_t) * 16);
684                         if (!sendmsg->payload.userStats->address.data)
685                                 Log_fatal("Out of memory");
686                         memset(sendmsg->payload.userStats->address.data, 0, 16);
687                         /* ipv4 representation as ipv6 address. Supposedly correct. */
688                         memcpy(&sendmsg->payload.userStats->address.data[12], &target->remote_tcp.sin_addr, 4);
689                         sendmsg->payload.userStats->address.len = 16;
690                 }
691                 /* BW */
692                 sendmsg->payload.userStats->has_bandwidth = true;
693                 sendmsg->payload.userStats->bandwidth = target->availableBandwidth;
694                 
695                 /* Onlinesecs */
696                 sendmsg->payload.userStats->has_onlinesecs = true;
697                 sendmsg->payload.userStats->onlinesecs = Timer_elapsed(&target->connectTime) / 1000000LL;               
698                 /* Idlesecs */
699                 sendmsg->payload.userStats->has_idlesecs = true;
700                 sendmsg->payload.userStats->idlesecs = Timer_elapsed(&target->idleTime) / 1000000LL;            
701                 Client_send_message(client, sendmsg);
702         }
703         break;
704                 /* Permission denied for all these messages. Not implemented. */
705         case ChannelRemove:
706         case ContextAction:
707         case ContextActionAdd:
708         case ACL:
709         case BanList:
710         case UserList:
711         case QueryUsers:
712                 sendPermissionDenied(client, "Not supported by uMurmur");
713                 break;
714                                 
715         default:
716                 Log_warn("Message %d not handled", msg->messageType);
717                 break;
718         }
719 out:
720         Msg_free(msg);
721         return;
722         
723 disconnect:
724         Msg_free(msg);
725         Client_close(client);
726 }
727