updates.
[silc.git] / lib / silcclient / client_notify.c
1 /*
2
3   client_notify.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2001 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21 /* This file includes the Notify packet handling. Notify packets are
22    important packets sent by the server. They tell different things to the
23    client such as nick changes, mode changes etc. */
24
25 #include "clientlibincludes.h"
26 #include "client_internal.h"
27
28 /* Called when notify is received and some async operation (such as command)
29    is required before processing the notify message. This calls again the
30    silc_client_notify_by_server and reprocesses the original notify packet. */
31
32 static void silc_client_notify_by_server_pending(void *context)
33 {
34   SilcPacketContext *p = (SilcPacketContext *)context;
35   silc_client_notify_by_server(p->context, p->sock, p);
36   silc_socket_free(p->sock);
37 }
38
39 /* Destructor for the pending command callback */
40
41 static void silc_client_notify_by_server_destructor(void *context)
42 {
43   silc_packet_context_free((SilcPacketContext *)context);
44 }
45
46 /* Resolve client information from server by Client ID. */
47
48 static void silc_client_notify_by_server_resolve(SilcClient client,
49                                                  SilcClientConnection conn,
50                                                  SilcPacketContext *packet,
51                                                  SilcClientID *client_id)
52 {
53   SilcPacketContext *p = silc_packet_context_dup(packet);
54   SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
55
56   p->context = (void *)client;
57   p->sock = silc_socket_dup(conn->sock);
58
59   silc_client_send_command(client, conn, SILC_COMMAND_WHOIS, ++conn->cmd_ident,
60                            1, 3, idp->data, idp->len);
61   silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
62                               silc_client_notify_by_server_destructor,
63                               silc_client_notify_by_server_pending, p);
64   silc_buffer_free(idp);
65 }
66
67 /* Received notify message from server */
68
69 void silc_client_notify_by_server(SilcClient client,
70                                   SilcSocketConnection sock,
71                                   SilcPacketContext *packet)
72 {
73   SilcBuffer buffer = packet->buffer;
74   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
75   SilcNotifyPayload payload;
76   SilcNotifyType type;
77   SilcArgumentPayload args;
78
79   SilcIDPayload idp;
80   SilcClientID *client_id = NULL;
81   SilcChannelID *channel_id = NULL;
82   SilcClientEntry client_entry;
83   SilcClientEntry client_entry2;
84   SilcChannelEntry channel;
85   SilcChannelUser chu;
86   SilcIDCacheEntry id_cache = NULL;
87   unsigned char *tmp;
88   uint32 tmp_len, mode;
89
90   payload = silc_notify_payload_parse(buffer);
91   if (!payload)
92     goto out;
93
94   type = silc_notify_get_type(payload);
95   args = silc_notify_get_args(payload);
96   if (!args)
97     goto out;
98
99   switch(type) {
100   case SILC_NOTIFY_TYPE_NONE:
101     /* Notify application */
102     client->ops->notify(client, conn, type, 
103                         silc_argument_get_arg_type(args, 1, NULL));
104     break;
105
106   case SILC_NOTIFY_TYPE_INVITE:
107     /* 
108      * Someone invited me to a channel. Find Client and Channel entries
109      * for the application.
110      */
111     
112     /* Get Channel ID */
113     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
114     if (!tmp)
115       goto out;
116
117     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
118     if (!channel_id)
119       goto out;
120
121     /* Get the channel entry */
122     channel = NULL;
123     if (silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
124                                 &id_cache))
125       channel = (SilcChannelEntry)id_cache->context;
126
127     /* Get sender Client ID */
128     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
129     if (!tmp)
130       goto out;
131
132     client_id = silc_id_payload_parse_id(tmp, tmp_len);
133     if (!client_id)
134       goto out;
135
136     /* Find Client entry and if not found query it */
137     client_entry = silc_client_get_client_by_id(client, conn, client_id);
138     if (!client_entry) {
139       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
140       goto out;
141     }
142
143     /* Get the channel name */
144     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
145     if (!tmp)
146       goto out;
147
148     /* Notify application */
149     client->ops->notify(client, conn, type, channel, tmp, client_entry);
150     break;
151
152   case SILC_NOTIFY_TYPE_JOIN:
153     /*
154      * Someone has joined to a channel. Get their ID and nickname and
155      * cache them for later use.
156      */
157
158     /* Get Client ID */
159     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
160     if (!tmp)
161       goto out;
162
163     client_id = silc_id_payload_parse_id(tmp, tmp_len);
164     if (!client_id)
165       goto out;
166
167     /* Find Client entry and if not found query it */
168     client_entry = silc_client_get_client_by_id(client, conn, client_id);
169     if (!client_entry) {
170       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
171       goto out;
172     }
173
174     /* If nickname or username hasn't been resolved, do so */
175     if (!client_entry->nickname || !client_entry->username) {
176       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
177       goto out;
178     }
179
180     /* Get Channel ID */
181     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
182     if (!tmp)
183       goto out;
184
185     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
186     if (!channel_id)
187       goto out;
188
189     /* Get channel entry */
190     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
191                                  &id_cache))
192       break;
193
194     channel = (SilcChannelEntry)id_cache->context;
195
196     /* Add client to channel */
197     if (client_entry != conn->local_entry) {
198       chu = silc_calloc(1, sizeof(*chu));
199       chu->client = client_entry;
200       silc_list_add(channel->clients, chu);
201     }
202
203     /* XXX add support for multiple same nicks on same channel. Check
204        for them here */
205
206     /* Notify application. The channel entry is sent last as this notify
207        is for channel but application don't know it from the arguments
208        sent by server. */
209     client->ops->notify(client, conn, type, client_entry, channel);
210     break;
211
212   case SILC_NOTIFY_TYPE_LEAVE:
213     /*
214      * Someone has left a channel. We will remove it from the channel but
215      * we'll keep it in the cache in case we'll need it later.
216      */
217     
218     /* Get Client ID */
219     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
220     if (!tmp)
221       goto out;
222
223     client_id = silc_id_payload_parse_id(tmp, tmp_len);
224     if (!client_id)
225       goto out;
226
227     /* Find Client entry */
228     client_entry = 
229       silc_client_get_client_by_id(client, conn, client_id);
230     if (!client_entry)
231       goto out;
232
233     /* Get channel entry */
234     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
235                                 SILC_ID_CHANNEL);
236     if (!channel_id)
237       goto out;
238     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
239                                  &id_cache))
240       break;
241
242     channel = (SilcChannelEntry)id_cache->context;
243
244     /* Remove client from channel */
245     silc_list_start(channel->clients);
246     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
247       if (chu->client == client_entry) {
248         silc_list_del(channel->clients, chu);
249         silc_free(chu);
250         break;
251       }
252     }
253
254     /* Notify application. The channel entry is sent last as this notify
255        is for channel but application don't know it from the arguments
256        sent by server. */
257     client->ops->notify(client, conn, type, client_entry, channel);
258     break;
259
260   case SILC_NOTIFY_TYPE_SIGNOFF:
261     /*
262      * Someone left SILC. We'll remove it from all channels and from cache.
263      */
264
265     /* Get Client ID */
266     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
267     if (!tmp)
268       goto out;
269
270     client_id = silc_id_payload_parse_id(tmp, tmp_len);
271     if (!client_id)
272       goto out;
273
274     /* Find Client entry */
275     client_entry = 
276       silc_client_get_client_by_id(client, conn, client_id);
277     if (!client_entry)
278       goto out;
279
280     /* Remove from all channels */
281     silc_client_remove_from_channels(client, conn, client_entry);
282
283     /* Remove from cache */
284     silc_idcache_del_by_context(conn->client_cache, client_entry);
285
286     /* Get signoff message */
287     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
288     if (tmp_len > 128)
289       tmp = NULL;
290
291     /* Notify application */
292     client->ops->notify(client, conn, type, client_entry, tmp);
293
294     /* Free data */
295     if (client_entry->nickname)
296       silc_free(client_entry->nickname);
297     if (client_entry->server)
298       silc_free(client_entry->server);
299     if (client_entry->id)
300       silc_free(client_entry->id);
301     if (client_entry->send_key)
302       silc_cipher_free(client_entry->send_key);
303     if (client_entry->receive_key)
304       silc_cipher_free(client_entry->receive_key);
305     break;
306
307   case SILC_NOTIFY_TYPE_TOPIC_SET:
308     /*
309      * Someone set the topic on a channel.
310      */
311
312     /* Get Client ID */
313     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
314     if (!tmp)
315       goto out;
316
317     client_id = silc_id_payload_parse_id(tmp, tmp_len);
318     if (!client_id)
319       goto out;
320
321     /* Find Client entry */
322     client_entry = 
323       silc_client_get_client_by_id(client, conn, client_id);
324     if (!client_entry)
325       goto out;
326
327     /* Get topic */
328     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
329     if (!tmp)
330       goto out;
331
332     /* Get channel entry */
333     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
334                                 SILC_ID_CHANNEL);
335     if (!channel_id)
336       goto out;
337     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
338                                  &id_cache))
339       break;
340
341     channel = (SilcChannelEntry)id_cache->context;
342
343     /* Notify application. The channel entry is sent last as this notify
344        is for channel but application don't know it from the arguments
345        sent by server. */
346     client->ops->notify(client, conn, type, client_entry, tmp, channel);
347     break;
348
349   case SILC_NOTIFY_TYPE_NICK_CHANGE:
350     /*
351      * Someone changed their nickname. If we don't have entry for the new
352      * ID we will query it and return here after it's done. After we've
353      * returned we fetch the old entry and free it and notify the 
354      * application.
355      */
356
357     /* Get old Client ID */
358     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
359     if (!tmp)
360       goto out;
361
362     client_id = silc_id_payload_parse_id(tmp, tmp_len);
363     if (!client_id)
364       goto out;
365
366     /* Ignore my ID */
367     if (SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
368       break;
369
370     /* Find old Client entry */
371     client_entry = silc_client_get_client_by_id(client, conn, client_id);
372     if (!client_entry)
373       goto out;
374     silc_free(client_id);
375
376     /* Get new Client ID */
377     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
378     if (!tmp)
379       goto out;
380
381     client_id = silc_id_payload_parse_id(tmp, tmp_len);
382     if (!client_id)
383       goto out;
384
385     /* Find Client entry and if not found resolve it */
386     client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
387     if (!client_entry2) {
388       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
389       goto out;
390     }
391
392     /* Remove the old from cache */
393     silc_idcache_del_by_context(conn->client_cache, client_entry);
394
395     /* Replace old ID entry with new one on all channels. */
396     silc_client_replace_from_channels(client, conn, client_entry,
397                                       client_entry2);
398
399     /* Notify application */
400     client->ops->notify(client, conn, type, client_entry, client_entry2);
401
402     /* Free data */
403     if (client_entry->nickname)
404       silc_free(client_entry->nickname);
405     if (client_entry->server)
406       silc_free(client_entry->server);
407     if (client_entry->id)
408       silc_free(client_entry->id);
409     if (client_entry->send_key)
410       silc_cipher_free(client_entry->send_key);
411     if (client_entry->receive_key)
412       silc_cipher_free(client_entry->receive_key);
413     silc_free(client_entry);
414     break;
415
416   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
417     /*
418      * Someone changed a channel mode
419      */
420
421     /* Get Client ID */
422     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
423     if (!tmp)
424       goto out;
425
426     idp = silc_id_payload_parse_data(tmp, tmp_len);
427     if (!idp)
428       goto out;
429
430     /* Find Client entry */
431     if (silc_id_payload_get_type(idp) == SILC_ID_CLIENT) {
432       client_id = silc_id_payload_parse_id(tmp, tmp_len);
433       if (!client_id) {
434         silc_id_payload_free(idp);
435         goto out;
436       }
437
438       client_entry = silc_client_get_client_by_id(client, conn, client_id);
439       if (!client_entry) {
440         silc_id_payload_free(idp);
441         goto out;
442       }
443     } else {
444       client_entry = NULL;
445     }
446
447     silc_id_payload_free(idp);
448
449     /* Get the mode */
450     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
451     if (!tmp)
452       goto out;
453
454     SILC_GET32_MSB(mode, tmp);
455
456     /* Get channel entry */
457     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
458                                 SILC_ID_CHANNEL);
459     if (!channel_id)
460       goto out;
461     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
462                                  &id_cache))
463       break;
464
465     channel = (SilcChannelEntry)id_cache->context;
466
467     /* Save the new mode */
468     channel->mode = mode;
469
470     /* Get the hmac */
471     tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
472     if (tmp) {
473       unsigned char hash[32];
474
475       if (channel->hmac)
476         silc_hmac_free(channel->hmac);
477       if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
478         goto out;
479
480       silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8,
481                      hash);
482       silc_hmac_set_key(channel->hmac, hash, 
483                         silc_hash_len(channel->hmac->hash));
484       memset(hash, 0, sizeof(hash));
485     }
486
487     /* Notify application. The channel entry is sent last as this notify
488        is for channel but application don't know it from the arguments
489        sent by server. */
490     client->ops->notify(client, conn, type, client_entry, mode, NULL, 
491                         tmp, channel);
492     break;
493
494   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
495     /*
496      * Someone changed user's mode on a channel
497      */
498
499     /* Get Client ID */
500     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
501     if (!tmp)
502       goto out;
503
504     client_id = silc_id_payload_parse_id(tmp, tmp_len);
505     if (!client_id)
506       goto out;
507
508     /* Find Client entry */
509     client_entry = 
510       silc_client_get_client_by_id(client, conn, client_id);
511     if (!client_entry)
512       goto out;
513
514     /* Get the mode */
515     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
516     if (!tmp)
517       goto out;
518
519     SILC_GET32_MSB(mode, tmp);
520
521     /* Get target Client ID */
522     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
523     if (!tmp)
524       goto out;
525
526     silc_free(client_id);
527     client_id = silc_id_payload_parse_id(tmp, tmp_len);
528     if (!client_id)
529       goto out;
530
531     /* Find target Client entry */
532     client_entry2 = 
533       silc_client_get_client_by_id(client, conn, client_id);
534     if (!client_entry2)
535       goto out;
536
537     /* Get channel entry */
538     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
539                                 SILC_ID_CHANNEL);
540     if (!channel_id)
541       goto out;
542     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
543                                  &id_cache))
544       break;
545
546     channel = (SilcChannelEntry)id_cache->context;
547
548     /* Save the mode */
549     silc_list_start(channel->clients);
550     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
551       if (chu->client == client_entry) {
552         chu->mode = mode;
553         break;
554       }
555     }
556
557     /* Notify application. The channel entry is sent last as this notify
558        is for channel but application don't know it from the arguments
559        sent by server. */
560     client->ops->notify(client, conn, type, client_entry, mode, 
561                         client_entry2, channel);
562     break;
563
564   case SILC_NOTIFY_TYPE_MOTD:
565     /*
566      * Received Message of the day
567      */
568
569     /* Get motd */
570     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
571     if (!tmp)
572       goto out;
573     
574     /* Notify application */
575     client->ops->notify(client, conn, type, tmp);
576     break;
577
578   case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
579     /*
580      * Router has enforced a new ID to a channel. Let's change the old
581      * ID to the one provided here.
582      */
583
584     /* Get the old ID */
585     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
586     if (!tmp)
587       goto out;
588     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
589     if (!channel_id)
590       goto out;
591     
592     /* Get the channel entry */
593     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
594                                  &id_cache))
595       break;
596
597     channel = (SilcChannelEntry)id_cache->context;
598
599     /* Free the old ID */
600     silc_free(channel->id);
601
602     /* Get the new ID */
603     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
604     if (!tmp)
605       goto out;
606     channel->id = silc_id_payload_parse_id(tmp, tmp_len);
607     if (!channel->id)
608       goto out;
609
610     id_cache->id = (void *)channel->id;
611
612     /* Notify application */
613     client->ops->notify(client, conn, type, channel, channel);
614     break;
615
616   case SILC_NOTIFY_TYPE_KICKED:
617     /*
618      * A client (maybe me) was kicked from a channel
619      */
620
621     /* Get Client ID */
622     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
623     if (!tmp)
624       goto out;
625
626     client_id = silc_id_payload_parse_id(tmp, tmp_len);
627     if (!client_id)
628       goto out;
629
630     /* Find Client entry */
631     client_entry = silc_client_get_client_by_id(client, conn, client_id);
632     if (!client_entry)
633       goto out;
634
635     /* Get channel entry */
636     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
637                                 SILC_ID_CHANNEL);
638     if (!channel_id)
639       goto out;
640     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
641                                  &id_cache))
642       break;
643
644     channel = (SilcChannelEntry)id_cache->context;
645
646     /* Get comment */
647     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
648
649     /* Notify application. The channel entry is sent last as this notify
650        is for channel but application don't know it from the arguments
651        sent by server. */
652     client->ops->notify(client, conn, type, client_entry, tmp, channel);
653
654     /* If I was kicked from channel, remove the channel */
655     if (client_entry == conn->local_entry) {
656       if (conn->current_channel == channel)
657         conn->current_channel = NULL;
658       silc_idcache_del_by_id(conn->channel_cache, channel->id);
659       silc_free(channel->channel_name);
660       silc_free(channel->id);
661       silc_free(channel->key);
662       silc_cipher_free(channel->channel_key);
663       silc_free(channel);
664     }
665     break;
666
667   case SILC_NOTIFY_TYPE_KILLED:
668     /*
669      * A client (maybe me) was killed from the network.
670      */
671
672     /* Get Client ID */
673     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
674     if (!tmp)
675       goto out;
676
677     client_id = silc_id_payload_parse_id(tmp, tmp_len);
678     if (!client_id)
679       goto out;
680
681     /* Find Client entry */
682     client_entry = silc_client_get_client_by_id(client, conn, client_id);
683     if (!client_entry)
684       goto out;
685
686     /* Get comment */
687     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
688
689     /* Notify application. */
690     client->ops->notify(client, conn, type, client_entry, tmp);
691
692     if (client_entry != conn->local_entry) {
693       /* Remove client from all channels */
694       silc_client_remove_from_channels(client, conn, client_entry);
695       silc_idcache_del_by_context(conn->client_cache, client_entry);
696       if (client_entry->nickname)
697         silc_free(client_entry->nickname);
698       if (client_entry->server)
699         silc_free(client_entry->server);
700       if (client_entry->id)
701         silc_free(client_entry->id);
702       if (client_entry->send_key)
703         silc_cipher_free(client_entry->send_key);
704       if (client_entry->receive_key)
705         silc_cipher_free(client_entry->receive_key);
706       silc_free(client_entry);
707     }
708
709     break;
710     
711   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
712     {
713       /*
714        * A server quit the SILC network and some clients must be removed
715        * from channels as they quit as well.
716        */
717       SilcClientEntry *clients = NULL;
718       uint32 clients_count = 0;
719       int i;
720
721       for (i = 1; i < silc_argument_get_arg_num(args); i++) {
722         /* Get Client ID */
723         tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
724         if (tmp) {
725           client_id = silc_id_payload_parse_id(tmp, tmp_len);
726           if (!client_id)
727             goto out;
728           
729           /* Get the client entry */
730           client_entry = silc_client_get_client_by_id(client, conn, client_id);
731           if (client_entry) {
732             clients = silc_realloc(clients, sizeof(*clients) * 
733                                    (clients_count + 1));
734             clients[clients_count] = client_entry;
735             clients_count++;
736           }
737           silc_free(client_id);
738         }
739       }
740       client_id = NULL;
741
742       /* Notify application. We don't keep server entries so the server
743          entry is returned as NULL. The client's are returned as array
744          of SilcClientEntry pointers. */
745       client->ops->notify(client, conn, type, NULL, clients, clients_count);
746
747       for (i = 0; i < clients_count; i++) {
748         /* Remove client from all channels */
749         client_entry = clients[i];
750         if (client_entry == conn->local_entry)
751           continue;
752
753         silc_client_remove_from_channels(client, conn, client_entry);
754         silc_idcache_del_by_context(conn->client_cache, client_entry);
755         if (client_entry->nickname)
756           silc_free(client_entry->nickname);
757         if (client_entry->server)
758           silc_free(client_entry->server);
759         if (client_entry->id)
760           silc_free(client_entry->id);
761         if (client_entry->send_key)
762           silc_cipher_free(client_entry->send_key);
763         if (client_entry->receive_key)
764           silc_cipher_free(client_entry->receive_key);
765         silc_free(client_entry);
766       }
767       silc_free(clients);
768
769     }
770     break;
771
772   default:
773     break;
774   }
775
776  out:
777   silc_notify_payload_free(payload);
778   if (client_id)
779     silc_free(client_id);
780   if (channel_id)
781     silc_free(channel_id);
782 }