Fixed server crash when setting Access token while connected.
[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         switch (msg->messageType) {
81         case Authenticate:
82                 Log_debug("Authenticate message received");
83                 
84                 if (IS_AUTH(client) || !msg->payload.authenticate->username) {
85                         /* Authenticate message might be sent when a token is set by the user.*/
86                         if (msg->payload.authenticate->n_tokens > 0) {
87                                 Log_debug("Tokens in auth message from %s", client->username);
88                         }
89                         break;
90                 }
91                 
92                 client->authenticated = true;
93                 
94                 client_itr = NULL;
95                 while (Client_iterate(&client_itr) != NULL) {
96                         if (!IS_AUTH(client_itr))
97                                 continue;
98                         if (client_itr->username && strncmp(client_itr->username, msg->payload.authenticate->username, MAX_TEXT) == 0) {
99                                 char buf[64];
100                                 sprintf(buf, "Username already in use");
101                                 Log_debug("Username already in use");
102                                 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__UsernameInUse);
103                                 goto disconnect;
104                         }                               
105                 }
106                 if (strlen(getStrConf(PASSPHRASE)) > 0) {
107                         if (!msg->payload.authenticate->password || strncmp(getStrConf(PASSPHRASE), msg->payload.authenticate->password, MAX_TEXT) != 0) {
108                                 char buf[64];
109                                 sprintf(buf, "Wrong server password");
110                                 sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__WrongServerPW);
111                                 Log_debug("Wrong server password: %s", msg->payload.authenticate->password);
112                                 goto disconnect;
113                         }
114                 }                               
115                 if (strlen(msg->payload.authenticate->username) == 0 ||
116                         strlen(msg->payload.authenticate->username) >= MAX_TEXT) { /* XXX - other invalid names? */
117                         char buf[64];
118                         sprintf(buf, "Invalid username");
119                         Log_debug("Invalid username");
120                         sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__InvalidUsername);
121                         goto disconnect;
122                 }                               
123
124                 if (Client_count() >= getIntConf(MAX_CLIENTS)) {
125                         char buf[64];
126                         sprintf(buf, "Server is full (max %d users)", getIntConf(MAX_CLIENTS));
127                         sendServerReject(client, buf, MUMBLE_PROTO__REJECT__REJECT_TYPE__ServerFull);
128                         goto disconnect;
129                 }
130                 
131                 /* Name & password */
132                 client->username = strdup(msg->payload.authenticate->username);                         
133                 
134                 /* Setup UDP encryption */
135                 CryptState_init(&client->cryptState);
136                 CryptState_genKey(&client->cryptState);
137                 sendmsg = Msg_create(CryptSetup);
138                 sendmsg->payload.cryptSetup->has_key = true;
139                 sendmsg->payload.cryptSetup->key.data = client->cryptState.raw_key;
140                 sendmsg->payload.cryptSetup->key.len = AES_BLOCK_SIZE;
141                 sendmsg->payload.cryptSetup->has_server_nonce = true;
142                 sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.encrypt_iv;
143                 sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
144                 sendmsg->payload.cryptSetup->has_client_nonce = true;
145                 sendmsg->payload.cryptSetup->client_nonce.data = client->cryptState.decrypt_iv;
146                 sendmsg->payload.cryptSetup->client_nonce.len = AES_BLOCK_SIZE;
147                 Client_send_message(client, sendmsg);
148
149                 /* Channel stuff */
150                 Chan_userJoin(defaultChan, client); /* Join default channel */
151
152                 /* Codec version */             
153                 Log_debug("Client %d has %d CELT codecs", client->sessionId,
154                                   msg->payload.authenticate->n_celt_versions);
155                 if (msg->payload.authenticate->n_celt_versions > 0) {
156                         int i;
157                         codec_t *codec_itr;
158                         client->codec_count = msg->payload.authenticate->n_celt_versions;
159                         
160                         for (i = 0; i < client->codec_count; i++)
161                         Client_codec_add(client, msg->payload.authenticate->celt_versions[i]);
162                         codec_itr = NULL;
163                         while (Client_codec_iterate(client, &codec_itr) != NULL)
164                                 Log_debug("Client %d CELT codec ver 0x%x", client->sessionId, codec_itr->codec);
165                                 
166                 } else {
167                         Client_codec_add(client, (int32_t)0x8000000a);
168                         client->codec_count = 1;
169                 }
170                 
171                 recheckCodecVersions();
172                 
173                 sendmsg = Msg_create(CodecVersion);
174                 sendmsg->payload.codecVersion->alpha = iCodecAlpha;
175                 sendmsg->payload.codecVersion->beta = iCodecBeta;
176                 sendmsg->payload.codecVersion->prefer_alpha = bPreferAlpha;
177                 Client_send_message(client, sendmsg);
178                 
179                 /* Iterate channels and send channel info */
180                 ch_itr = NULL;
181                 while (Chan_iterate(&ch_itr) != NULL) {
182                         sendmsg = Msg_create(ChannelState);
183                         sendmsg->payload.channelState->has_channel_id = true;
184                         sendmsg->payload.channelState->channel_id = ch_itr->id;
185                         if (ch_itr->id != 0) {
186                                 sendmsg->payload.channelState->has_parent = true;
187                                 sendmsg->payload.channelState->parent = ch_itr->parent->id;
188                         }
189                         sendmsg->payload.channelState->name = strdup(ch_itr->name);
190                         if (ch_itr->desc)
191                                 sendmsg->payload.channelState->description = strdup(ch_itr->desc);
192                         Log_debug("Send channel info: %s", sendmsg->payload.channelState->name);
193                         Client_send_message(client, sendmsg);                   
194                 }
195
196                 /* Iterate channels and send channel links info */
197                 ch_itr = NULL;
198                 while (Chan_iterate(&ch_itr) != NULL) {
199                         if (ch_itr->linkcount > 0) { /* Has links */
200                                 uint32_t *links;
201                                 int i = 0;
202                                 struct dlist *itr;
203                                 
204                                 sendmsg = Msg_create(ChannelState);
205                                 sendmsg->payload.channelState->has_channel_id = true;
206                                 sendmsg->payload.channelState->channel_id = ch_itr->id;
207                                 sendmsg->payload.channelState->n_links = ch_itr->linkcount;
208                                 
209                                 links = (uint32_t *)malloc(ch_itr->linkcount * sizeof(uint32_t));
210                                 list_iterate(itr, &ch_itr->channel_links) { /* Iterate links */
211                                         channel_t *ch;
212                                         ch = list_get_entry(itr, channel_t, link_node);
213                                         links[i++] = ch->id;
214                                 }
215                                 sendmsg->payload.channelState->links = links;
216                                 Client_send_message(client, sendmsg);
217                         }
218                 }
219                 
220                 /* Send user state for connecting user to other users */
221                 sendmsg = Msg_create(UserState);
222                 sendmsg->payload.userState->has_session = true;
223                 sendmsg->payload.userState->session = client->sessionId;
224                 sendmsg->payload.userState->has_user_id = true;
225                 sendmsg->payload.userState->user_id = client->sessionId;
226                 sendmsg->payload.userState->name = strdup(client->username);
227                 sendmsg->payload.userState->has_channel_id = true;
228                 sendmsg->payload.userState->channel_id = ((channel_t *)client->channel)->id;
229                 
230                 Client_send_message_except(client, sendmsg);
231
232                 client_itr = NULL;
233                 while (Client_iterate(&client_itr) != NULL) {
234                         if (!IS_AUTH(client_itr))
235                                 continue;
236                         sendmsg = Msg_create(UserState);
237                         sendmsg->payload.userState->has_session = true;
238                         sendmsg->payload.userState->session = client_itr->sessionId;
239                         sendmsg->payload.userState->name = strdup(client_itr->username);
240                         sendmsg->payload.userState->has_channel_id = true;
241                         sendmsg->payload.userState->channel_id = ((channel_t *)client_itr->channel)->id;
242
243                         /* Only self_mute/deaf supported */
244                         if (client_itr->deaf) {
245                                 sendmsg->payload.userState->has_self_deaf = true;
246                                 sendmsg->payload.userState->self_deaf = true;
247                         }
248                         if (client_itr->mute) {
249                                 sendmsg->payload.userState->has_self_mute = true;
250                                 sendmsg->payload.userState->self_mute = true;
251                         }
252                         Client_send_message(client, sendmsg);
253                 }
254
255                 /* Sync message */
256                 sendmsg = Msg_create(ServerSync);
257                 sendmsg->payload.serverSync->has_session = true;
258                 sendmsg->payload.serverSync->session = client->sessionId;
259                 sendmsg->payload.serverSync->welcome_text = strdup(getStrConf(WELCOMETEXT));
260                 sendmsg->payload.serverSync->has_max_bandwidth = true;
261                 sendmsg->payload.serverSync->max_bandwidth = getIntConf(MAX_BANDWIDTH);
262                 sendmsg->payload.serverSync->has_allow_html = true;
263                 sendmsg->payload.serverSync->allow_html = true; /* Support this? */
264                 Client_send_message(client, sendmsg);
265                 
266                 Log_info_client(client, "User %s authenticated", client->username);
267                 break;
268                 
269         case Ping:
270                 if (msg->payload.ping->has_good)
271                         client->cryptState.uiRemoteGood = msg->payload.ping->good;
272                 if (msg->payload.ping->has_late)
273                         client->cryptState.uiRemoteLate = msg->payload.ping->late;
274                 if (msg->payload.ping->has_lost)
275                         client->cryptState.uiRemoteLost = msg->payload.ping->lost;
276                 if (msg->payload.ping->has_resync)
277                         client->cryptState.uiRemoteResync = msg->payload.ping->resync;
278
279                 Log_debug("Ping <-: %d %d %d %d",
280                                   client->cryptState.uiRemoteGood, client->cryptState.uiRemoteLate,
281                                   client->cryptState.uiRemoteLost, client->cryptState.uiRemoteResync
282                         );
283                 
284                 /* Ignoring the double values since they don't seem to be used */
285                 
286                 sendmsg = Msg_create(Ping);
287
288                 sendmsg->payload.ping->timestamp = msg->payload.ping->timestamp;
289                 sendmsg->payload.ping->has_timestamp = true;
290                 sendmsg->payload.ping->good = client->cryptState.uiGood;
291                 sendmsg->payload.ping->has_good = true;
292                 sendmsg->payload.ping->late = client->cryptState.uiLate;
293                 sendmsg->payload.ping->has_late = true;
294                 sendmsg->payload.ping->lost = client->cryptState.uiLost;
295                 sendmsg->payload.ping->has_lost = true;
296                 sendmsg->payload.ping->resync = client->cryptState.uiResync;
297                 sendmsg->payload.ping->has_resync = true;
298
299                 Client_send_message(client, sendmsg);
300                 Log_debug("Ping ->: %d %d %d %d",
301                                   client->cryptState.uiGood, client->cryptState.uiLate,
302                                   client->cryptState.uiLost, client->cryptState.uiResync);
303
304                 break;
305         case CryptSetup:
306                 Log_debug("Voice channel crypt resync requested");
307                 if (!msg->payload.cryptSetup->has_client_nonce) {
308                         sendmsg = Msg_create(CryptSetup);
309                         sendmsg->payload.cryptSetup->has_server_nonce = true;
310                         sendmsg->payload.cryptSetup->server_nonce.data = client->cryptState.decrypt_iv;
311                         sendmsg->payload.cryptSetup->server_nonce.len = AES_BLOCK_SIZE;
312                         Client_send_message(client, sendmsg);
313                 } else {
314                         memcpy(client->cryptState.decrypt_iv, msg->payload.cryptSetup->client_nonce.data, AES_BLOCK_SIZE);
315                         client->cryptState.uiResync++;
316                 }
317                 break;
318         case UserState:
319                 /* Only allow state changes for for the self user */
320                 if (msg->payload.userState->has_session &&
321                         msg->payload.userState->session != client->sessionId) {
322                         sendPermissionDenied(client, "Permission denied");
323                         break;
324                 }
325                 if (msg->payload.userState->has_user_id || msg->payload.userState->has_mute ||
326                         msg->payload.userState->has_deaf || msg->payload.userState->has_suppress ||
327                         msg->payload.userState->has_texture) {
328                         
329                         sendPermissionDenied(client, "Not supported by uMurmur");
330                         break;
331                 }
332                 if (msg->payload.userState->has_self_deaf) {
333                         client->deaf = msg->payload.userState->self_deaf;
334                 }
335                 if (msg->payload.userState->has_self_mute) {
336                         client->mute = msg->payload.userState->self_mute;                       
337                 }
338                 if (msg->payload.userState->has_channel_id) {
339                         int leave_id;
340                         if (!Chan_userJoin_id_test(msg->payload.userState->channel_id))
341                                 break;
342                         leave_id = Chan_userJoin_id(msg->payload.userState->channel_id, client);
343                         if (leave_id > 0) {
344                                 Log_debug("Removing channel ID %d", leave_id);
345                                 sendmsg = Msg_create(ChannelRemove);
346                                 sendmsg->payload.channelRemove->channel_id = leave_id;
347                         }
348                 }
349                 if (msg->payload.userState->plugin_context != NULL) {
350                         if (client->context)
351                                 free(client->context);
352                         client->context = strdup(msg->payload.userState->plugin_context);
353                         if (client->context == NULL)
354                                 Log_fatal("Out of memory");
355                         
356                         break; /* Don't inform other users about this state */
357                 }
358                 
359                 /* Re-use message */
360                 Msg_inc_ref(msg);
361                 msg->payload.userState->has_actor = true;
362                 msg->payload.userState->actor = client->sessionId;
363                 Client_send_message_except(NULL, msg);
364
365                 /* Need to send remove channel message _after_ UserState message */
366                 if (sendmsg != NULL)
367                         Client_send_message_except(NULL, sendmsg);
368                 break;
369                 
370         case TextMessage:
371                 msg->payload.textMessage->has_actor = true;
372                 msg->payload.textMessage->actor = client->sessionId;
373
374                 /* XXX - HTML is allowed and can't be turned off */
375                 if (msg->payload.textMessage->n_tree_id > 0) {
376                         sendPermissionDenied(client, "Tree message not supported");
377                         break;
378                 }
379                         
380                 if (msg->payload.textMessage->n_channel_id > 0) { /* To channel */
381                         int i;
382                         channel_t *ch_itr;
383                         for (i = 0; i < msg->payload.textMessage->n_channel_id; i++) {
384                                 ch_itr = NULL;
385                                 do {
386                                         Chan_iterate(&ch_itr);
387                                 } while (ch_itr != NULL && ch_itr->id != msg->payload.textMessage->channel_id[i]);
388                                 if (ch_itr != NULL) {
389                                         struct dlist *itr;
390                                         list_iterate(itr, &ch_itr->clients) {
391                                                 client_t *c;
392                                                 c = list_get_entry(itr, client_t, chan_node);
393                                                 if (c != client && !c->deaf) {
394                                                         Msg_inc_ref(msg);
395                                                         Client_send_message(c, msg);
396                                                         Log_debug("Text message to session ID %d", c->sessionId);
397                                                 }
398                                         }
399                                 }
400                         } /* for */
401                 }
402                 if (msg->payload.textMessage->n_session > 0) { /* To user */
403                         int i;
404                         client_t *itr;
405                         for (i = 0; i < msg->payload.textMessage->n_session; i++) {
406                                 itr = NULL;
407                                 while (Client_iterate(&itr) != NULL) {
408                                         if (!IS_AUTH(itr))
409                                                 continue;
410                                         if (itr->sessionId == msg->payload.textMessage->session[i]) {
411                                                 if (!itr->deaf) {
412                                                         Msg_inc_ref(msg);
413                                                         Client_send_message(itr, msg);
414                                                         Log_debug("Text message to session ID %d", itr->sessionId);
415                                                 }
416                                                 break;
417                                         }
418                                 }
419                                 if (itr == NULL)
420                                         Log_warn("TextMessage: Session ID %d not found", msg->payload.textMessage->session[i]);
421                         } /* for */
422                 }
423                 break;
424
425         case VoiceTarget:
426         {
427                 int i, j, count, targetId = msg->payload.voiceTarget->id;
428                 struct _MumbleProto__VoiceTarget__Target *target;
429
430                 if (!targetId || targetId >= 0x1f)
431                         break;
432                 Voicetarget_add_id(client, targetId);
433                 count = msg->payload.voiceTarget->n_targets;
434                 if (!count)
435                         break;
436                 for (i = 0; i < count; i++) {
437                         target = msg->payload.voiceTarget->targets[i];
438                         for (j = 0; j < target->n_session; j++)
439                                 Voicetarget_add_session(client, targetId, target->session[j]);
440                         if (target->has_channel_id) {
441                                 bool_t linked = false, children = false;
442                                 if (target->has_links)
443                                         linked = target->links;
444                                 if (target->has_children)
445                                         children = target->children;
446                                 Voicetarget_add_channel(client, targetId, target->channel_id, linked, children);
447                         }
448                 }
449                 break;
450         }
451         case Version:
452                 Log_debug("Version message received");
453                 if (msg->payload.version->has_version) {
454                         client->version = msg->payload.version->version;
455                         Log_debug("Client version 0x%x", client->version);
456                 }
457                 if (msg->payload.version->release) {
458                         if (client->release) free(client->release);
459                         client->release = strdup(msg->payload.version->release);
460                         Log_debug("Client release %s", client->release);
461                 }
462                 if (msg->payload.version->os) {
463                         if (client->os) free(client->os);                       
464                         client->os = strdup(msg->payload.version->os);
465                         Log_debug("Client OS %s", client->os);
466                 }
467                 break;
468         case PermissionQuery:
469                 Msg_inc_ref(msg); /* Re-use message */
470                 msg->payload.permissionQuery->has_permissions = true;
471                 msg->payload.permissionQuery->permissions = PERM_DEFAULT;
472                 
473                 Client_send_message(client, msg);
474                 break;
475         case UDPTunnel:
476                 client->bUDP = false;
477                 Client_voiceMsg(client, msg->payload.UDPTunnel->packet.data, msg->payload.UDPTunnel->packet.len);
478             break;
479         case ChannelState:
480         {
481                 channel_t *ch_itr, *parent, *newchan;
482                 int leave_id;           
483                 /* Don't allow any changes to existing channels */
484                 if (msg->payload.channelState->has_channel_id) {
485                         sendPermissionDenied(client, "Not supported by uMurmur");
486                         break;
487                 }
488                 /* Must have parent */
489                 if (!msg->payload.channelState->has_parent) {
490                         sendPermissionDenied(client, "Not supported by uMurmur");
491                         break;
492                 }
493                 /* Must have name */
494                 if (msg->payload.channelState->name == NULL) {
495                         sendPermissionDenied(client, "Not supported by uMurmur");
496                         break;
497                 }
498                 /* Must be temporary channel */
499                 if (msg->payload.channelState->temporary != true) {
500                         sendPermissionDenied(client, "Only temporary channels are supported by uMurmur");
501                         break;
502                 }
503                 /* Check channel name is OK */
504                 if (strlen(msg->payload.channelState->name) > MAX_TEXT) {
505                         sendPermissionDenied(client, "Channel name too long");
506                         break;
507                 }
508                         
509                 parent = Chan_fromId(msg->payload.channelState->parent);
510                 if (parent == NULL)
511                         break;
512                 ch_itr = NULL;
513                 while (Chan_iterate_siblings(parent, &ch_itr) != NULL) {
514                         if (strcmp(ch_itr->name, msg->payload.channelState->name) == 0) {
515                                 sendPermissionDenied(client, "Channel already exists");
516                                 break;
517                         }
518                 }
519                 if (ch_itr != NULL)
520                         break;
521                 
522                 /* Disallow temporary channels as siblings to temporary channels */
523                 if (parent->temporary) {
524                         sendPermissionDenied(client, "Parent channel is temporary channel");
525                         break;
526                 }
527                         
528                 /* XXX - Murmur looks for "\\w" and sends perm denied if not found.
529                  * I don't know why so I don't do that here...
530                  */
531
532                 /* Create the channel */
533                 newchan = Chan_createChannel(msg->payload.channelState->name,
534                                                                          msg->payload.channelState->description);
535                 newchan->temporary = true;
536                 Chan_addChannel(parent, newchan);
537                 msg->payload.channelState->has_channel_id = true;
538                 msg->payload.channelState->channel_id = newchan->id;
539                 Msg_inc_ref(msg);
540                 Client_send_message_except(NULL, msg);
541
542                 /* Join the creating user */
543                 sendmsg = Msg_create(UserState);
544                 sendmsg->payload.userState->has_session = true;
545                 sendmsg->payload.userState->session = client->sessionId;
546                 sendmsg->payload.userState->has_channel_id = true;
547                 sendmsg->payload.userState->channel_id = newchan->id;
548                 Client_send_message_except(NULL, sendmsg);
549                 
550                 leave_id = Chan_userJoin(newchan, client);
551                 if (leave_id > 0) {
552                         Log_debug("Removing channel ID %d", leave_id);
553                         sendmsg = Msg_create(ChannelRemove);
554                         sendmsg->payload.channelRemove->channel_id = leave_id;
555                         Client_send_message_except(NULL, sendmsg);
556                 }
557         }               
558         break;
559
560                 /* Permission denied for all these messages. Not implemented. */
561         case ChannelRemove:
562         case ContextAction:
563         case ContextActionAdd:
564         case ACL:
565         case BanList:
566         case UserList:
567         case QueryUsers:
568                 sendPermissionDenied(client, "Not supported by uMurmur");
569                 break;
570                                 
571         default:
572                 Log_warn("Message %d not handled", msg->messageType);
573                 break;
574         }
575 out:
576         Msg_free(msg);
577         return;
578         
579 disconnect:
580         Msg_free(msg);
581         Client_close(client);
582 }
583