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