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                                      SILC_ID_CHANNEL, &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                                      SILC_ID_CHANNEL, &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                                      SILC_ID_CHANNEL, &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_id(conn->client_cache, SILC_ID_CLIENT, 
285                            client_entry->id);
286
287     /* Get signoff message */
288     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
289     if (tmp_len > 128)
290       tmp = NULL;
291
292     /* Notify application */
293     client->ops->notify(client, conn, type, client_entry, tmp);
294
295     /* Free data */
296     if (client_entry->nickname)
297       silc_free(client_entry->nickname);
298     if (client_entry->server)
299       silc_free(client_entry->server);
300     if (client_entry->id)
301       silc_free(client_entry->id);
302     if (client_entry->send_key)
303       silc_cipher_free(client_entry->send_key);
304     if (client_entry->receive_key)
305       silc_cipher_free(client_entry->receive_key);
306     break;
307
308   case SILC_NOTIFY_TYPE_TOPIC_SET:
309     /*
310      * Someone set the topic on a channel.
311      */
312
313     /* Get Client ID */
314     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
315     if (!tmp)
316       goto out;
317
318     client_id = silc_id_payload_parse_id(tmp, tmp_len);
319     if (!client_id)
320       goto out;
321
322     /* Find Client entry */
323     client_entry = 
324       silc_client_get_client_by_id(client, conn, client_id);
325     if (!client_entry)
326       goto out;
327
328     /* Get topic */
329     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
330     if (!tmp)
331       goto out;
332
333     /* Get channel entry */
334     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
335                                 SILC_ID_CHANNEL);
336     if (!channel_id)
337       goto out;
338     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
339                                      SILC_ID_CHANNEL, &id_cache))
340       break;
341
342     channel = (SilcChannelEntry)id_cache->context;
343
344     /* Notify application. The channel entry is sent last as this notify
345        is for channel but application don't know it from the arguments
346        sent by server. */
347     client->ops->notify(client, conn, type, client_entry, tmp, channel);
348     break;
349
350   case SILC_NOTIFY_TYPE_NICK_CHANGE:
351     /*
352      * Someone changed their nickname. If we don't have entry for the new
353      * ID we will query it and return here after it's done. After we've
354      * returned we fetch the old entry and free it and notify the 
355      * application.
356      */
357
358     /* Get old Client ID */
359     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
360     if (!tmp)
361       goto out;
362
363     client_id = silc_id_payload_parse_id(tmp, tmp_len);
364     if (!client_id)
365       goto out;
366
367     /* Ignore my ID */
368     if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
369       break;
370
371     /* Find old Client entry */
372     client_entry = silc_client_get_client_by_id(client, conn, client_id);
373     if (!client_entry)
374       goto out;
375     silc_free(client_id);
376
377     /* Get new Client ID */
378     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
379     if (!tmp)
380       goto out;
381
382     client_id = silc_id_payload_parse_id(tmp, tmp_len);
383     if (!client_id)
384       goto out;
385
386     /* Find Client entry and if not found resolve it */
387     client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
388     if (!client_entry2) {
389       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
390       goto out;
391     }
392
393     /* Remove the old from cache */
394     silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, 
395                            client_entry->id);
396
397     /* Replace old ID entry with new one on all channels. */
398     silc_client_replace_from_channels(client, conn, client_entry,
399                                       client_entry2);
400
401     /* Notify application */
402     client->ops->notify(client, conn, type, client_entry, client_entry2);
403
404     /* Free data */
405     if (client_entry->nickname)
406       silc_free(client_entry->nickname);
407     if (client_entry->server)
408       silc_free(client_entry->server);
409     if (client_entry->id)
410       silc_free(client_entry->id);
411     if (client_entry->send_key)
412       silc_cipher_free(client_entry->send_key);
413     if (client_entry->receive_key)
414       silc_cipher_free(client_entry->receive_key);
415     silc_free(client_entry);
416     break;
417
418   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
419     /*
420      * Someone changed a channel mode
421      */
422
423     /* Get Client ID */
424     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
425     if (!tmp)
426       goto out;
427
428     idp = silc_id_payload_parse_data(tmp, tmp_len);
429     if (!idp)
430       goto out;
431
432     /* Find Client entry */
433     if (silc_id_payload_get_type(idp) == SILC_ID_CLIENT) {
434       client_id = silc_id_payload_parse_id(tmp, tmp_len);
435       if (!client_id) {
436         silc_id_payload_free(idp);
437         goto out;
438       }
439
440       client_entry = silc_client_get_client_by_id(client, conn, client_id);
441       if (!client_entry) {
442         silc_id_payload_free(idp);
443         goto out;
444       }
445     } else {
446       client_entry = NULL;
447     }
448
449     silc_id_payload_free(idp);
450
451     /* Get the mode */
452     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
453     if (!tmp)
454       goto out;
455
456     SILC_GET32_MSB(mode, tmp);
457
458     /* Get channel entry */
459     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
460                                 SILC_ID_CHANNEL);
461     if (!channel_id)
462       goto out;
463     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
464                                      SILC_ID_CHANNEL, &id_cache))
465       break;
466
467     channel = (SilcChannelEntry)id_cache->context;
468
469     /* Save the new mode */
470     channel->mode = mode;
471
472     /* Get the hmac */
473     tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
474     if (tmp) {
475       unsigned char hash[32];
476
477       if (channel->hmac)
478         silc_hmac_free(channel->hmac);
479       if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
480         goto out;
481
482       silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8,
483                      hash);
484       silc_hmac_set_key(channel->hmac, hash, 
485                         silc_hash_len(channel->hmac->hash));
486       memset(hash, 0, sizeof(hash));
487     }
488
489     /* Notify application. The channel entry is sent last as this notify
490        is for channel but application don't know it from the arguments
491        sent by server. */
492     client->ops->notify(client, conn, type, client_entry, mode, NULL, 
493                         tmp, channel);
494     break;
495
496   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
497     /*
498      * Someone changed user's mode on a channel
499      */
500
501     /* Get Client ID */
502     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
503     if (!tmp)
504       goto out;
505
506     client_id = silc_id_payload_parse_id(tmp, tmp_len);
507     if (!client_id)
508       goto out;
509
510     /* Find Client entry */
511     client_entry = 
512       silc_client_get_client_by_id(client, conn, client_id);
513     if (!client_entry)
514       goto out;
515
516     /* Get the mode */
517     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
518     if (!tmp)
519       goto out;
520
521     SILC_GET32_MSB(mode, tmp);
522
523     /* Get target Client ID */
524     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
525     if (!tmp)
526       goto out;
527
528     silc_free(client_id);
529     client_id = silc_id_payload_parse_id(tmp, tmp_len);
530     if (!client_id)
531       goto out;
532
533     /* Find target Client entry */
534     client_entry2 = 
535       silc_client_get_client_by_id(client, conn, client_id);
536     if (!client_entry2)
537       goto out;
538
539     /* Get channel entry */
540     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
541                                 SILC_ID_CHANNEL);
542     if (!channel_id)
543       goto out;
544     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
545                                      SILC_ID_CHANNEL, &id_cache))
546       break;
547
548     channel = (SilcChannelEntry)id_cache->context;
549
550     /* Save the mode */
551     silc_list_start(channel->clients);
552     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
553       if (chu->client == client_entry) {
554         chu->mode = mode;
555         break;
556       }
557     }
558
559     /* Notify application. The channel entry is sent last as this notify
560        is for channel but application don't know it from the arguments
561        sent by server. */
562     client->ops->notify(client, conn, type, client_entry, mode, 
563                         client_entry2, channel);
564     break;
565
566   case SILC_NOTIFY_TYPE_MOTD:
567     /*
568      * Received Message of the day
569      */
570
571     /* Get motd */
572     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
573     if (!tmp)
574       goto out;
575     
576     /* Notify application */
577     client->ops->notify(client, conn, type, tmp);
578     break;
579
580   case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
581     /*
582      * Router has enforced a new ID to a channel. Let's change the old
583      * ID to the one provided here.
584      */
585
586     /* Get the old ID */
587     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
588     if (!tmp)
589       goto out;
590     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
591     if (!channel_id)
592       goto out;
593     
594     /* Get the channel entry */
595     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
596                                      SILC_ID_CHANNEL, &id_cache))
597       break;
598
599     channel = (SilcChannelEntry)id_cache->context;
600
601     /* Free the old ID */
602     silc_free(channel->id);
603
604     /* Get the new ID */
605     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
606     if (!tmp)
607       goto out;
608     channel->id = silc_id_payload_parse_id(tmp, tmp_len);
609     if (!channel->id)
610       goto out;
611
612     id_cache->id = (void *)channel->id;
613
614     /* Notify application */
615     client->ops->notify(client, conn, type, channel, channel);
616     break;
617
618   case SILC_NOTIFY_TYPE_KICKED:
619     /*
620      * A client (maybe me) was kicked from a channel
621      */
622
623     /* Get Client ID */
624     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
625     if (!tmp)
626       goto out;
627
628     client_id = silc_id_payload_parse_id(tmp, tmp_len);
629     if (!client_id)
630       goto out;
631
632     /* Find Client entry */
633     client_entry = silc_client_get_client_by_id(client, conn, client_id);
634     if (!client_entry)
635       goto out;
636
637     /* Get channel entry */
638     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
639                                 SILC_ID_CHANNEL);
640     if (!channel_id)
641       goto out;
642     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
643                                      SILC_ID_CHANNEL, &id_cache))
644       break;
645
646     channel = (SilcChannelEntry)id_cache->context;
647
648     /* Get comment */
649     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
650
651     /* Notify application. The channel entry is sent last as this notify
652        is for channel but application don't know it from the arguments
653        sent by server. */
654     client->ops->notify(client, conn, type, client_entry, tmp, channel);
655
656     /* If I was kicked from channel, remove the channel */
657     if (client_entry == conn->local_entry) {
658       if (conn->current_channel == channel)
659         conn->current_channel = NULL;
660       silc_idcache_del_by_id(conn->channel_cache, 
661                              SILC_ID_CHANNEL, channel->id);
662       silc_free(channel->channel_name);
663       silc_free(channel->id);
664       silc_free(channel->key);
665       silc_cipher_free(channel->channel_key);
666       silc_free(channel);
667     }
668     break;
669
670   case SILC_NOTIFY_TYPE_KILLED:
671     /*
672      * A client (maybe me) was killed from the network.
673      */
674
675     /* Get Client ID */
676     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
677     if (!tmp)
678       goto out;
679
680     client_id = silc_id_payload_parse_id(tmp, tmp_len);
681     if (!client_id)
682       goto out;
683
684     /* Find Client entry */
685     client_entry = silc_client_get_client_by_id(client, conn, client_id);
686     if (!client_entry)
687       goto out;
688
689     /* Get comment */
690     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
691
692     /* Notify application. */
693     client->ops->notify(client, conn, type, client_entry, tmp);
694
695     if (client_entry != conn->local_entry) {
696       /* Remove client from all channels */
697       silc_client_remove_from_channels(client, conn, client_entry);
698       silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, 
699                              client_entry->id);
700       if (client_entry->nickname)
701         silc_free(client_entry->nickname);
702       if (client_entry->server)
703         silc_free(client_entry->server);
704       if (client_entry->id)
705         silc_free(client_entry->id);
706       if (client_entry->send_key)
707         silc_cipher_free(client_entry->send_key);
708       if (client_entry->receive_key)
709         silc_cipher_free(client_entry->receive_key);
710       silc_free(client_entry);
711     }
712
713     break;
714     
715   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
716     {
717       /*
718        * A server quit the SILC network and some clients must be removed
719        * from channels as they quit as well.
720        */
721       SilcClientEntry *clients = NULL;
722       uint32 clients_count = 0;
723       int i;
724
725       for (i = 1; i < silc_argument_get_arg_num(args); i++) {
726         /* Get Client ID */
727         tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
728         if (tmp) {
729           client_id = silc_id_payload_parse_id(tmp, tmp_len);
730           if (!client_id)
731             goto out;
732           
733           /* Get the client entry */
734           client_entry = silc_client_get_client_by_id(client, conn, client_id);
735           if (client_entry) {
736             clients = silc_realloc(clients, sizeof(*clients) * 
737                                    (clients_count + 1));
738             clients[clients_count] = client_entry;
739             clients_count++;
740           }
741           silc_free(client_id);
742         }
743       }
744       client_id = NULL;
745
746       /* Notify application. We don't keep server entries so the server
747          entry is returned as NULL. The client's are returned as array
748          of SilcClientEntry pointers. */
749       client->ops->notify(client, conn, type, NULL, clients, clients_count);
750
751       for (i = 0; i < clients_count; i++) {
752         /* Remove client from all channels */
753         client_entry = clients[i];
754         if (client_entry == conn->local_entry)
755           continue;
756
757         silc_client_remove_from_channels(client, conn, client_entry);
758         silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, 
759                                client_entry->id);
760         if (client_entry->nickname)
761           silc_free(client_entry->nickname);
762         if (client_entry->server)
763           silc_free(client_entry->server);
764         if (client_entry->id)
765           silc_free(client_entry->id);
766         if (client_entry->send_key)
767           silc_cipher_free(client_entry->send_key);
768         if (client_entry->receive_key)
769           silc_cipher_free(client_entry->receive_key);
770         silc_free(client_entry);
771       }
772       silc_free(clients);
773
774     }
775     break;
776
777   default:
778     break;
779   }
780
781  out:
782   silc_notify_payload_free(payload);
783   if (client_id)
784     silc_free(client_id);
785   if (channel_id)
786     silc_free(channel_id);
787 }