47fd25b5328c0ad7d29fff810592f832ac0e1faa
[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 }
37
38 /* Destructor for the pending command callback */
39
40 static void silc_client_notify_by_server_destructor(void *context)
41 {
42   silc_packet_context_free((SilcPacketContext *)context);
43 }
44
45 /* Resolve client information from server by Client ID. */
46
47 static void silc_client_notify_by_server_resolve(SilcClient client,
48                                                  SilcClientConnection conn,
49                                                  SilcPacketContext *packet,
50                                                  SilcClientID *client_id)
51 {
52   SilcPacketContext *p = silc_packet_context_dup(packet);
53   SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
54
55   p->context = (void *)client;
56   p->sock = conn->sock;
57
58   silc_client_send_command(client, conn, SILC_COMMAND_WHOIS, ++conn->cmd_ident,
59                            1, 3, idp->data, idp->len);
60   silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
61                               silc_client_notify_by_server_destructor,
62                               silc_client_notify_by_server_pending, p);
63   silc_buffer_free(idp);
64 }
65
66 /* Received notify message from server */
67
68 void silc_client_notify_by_server(SilcClient client,
69                                   SilcSocketConnection sock,
70                                   SilcPacketContext *packet)
71 {
72   SilcBuffer buffer = packet->buffer;
73   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
74   SilcNotifyPayload payload;
75   SilcNotifyType type;
76   SilcArgumentPayload args;
77
78   SilcIDPayload idp;
79   SilcClientID *client_id = NULL;
80   SilcChannelID *channel_id = NULL;
81   SilcClientEntry client_entry;
82   SilcClientEntry client_entry2;
83   SilcChannelEntry channel;
84   SilcChannelUser chu;
85   SilcIDCacheEntry id_cache = NULL;
86   unsigned char *tmp;
87   uint32 tmp_len, mode;
88
89   payload = silc_notify_payload_parse(buffer);
90   if (!payload)
91     goto out;
92
93   type = silc_notify_get_type(payload);
94   args = silc_notify_get_args(payload);
95   if (!args)
96     goto out;
97
98   switch(type) {
99   case SILC_NOTIFY_TYPE_NONE:
100     /* Notify application */
101     client->ops->notify(client, conn, type, 
102                         silc_argument_get_arg_type(args, 1, NULL));
103     break;
104
105   case SILC_NOTIFY_TYPE_INVITE:
106     /* 
107      * Someone invited me to a channel. Find Client and Channel entries
108      * for the application.
109      */
110     
111     /* Get Channel ID */
112     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
113     if (!tmp)
114       goto out;
115
116     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
117     if (!channel_id)
118       goto out;
119
120     /* Get the channel entry */
121     channel = NULL;
122     if (silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
123                                      SILC_ID_CHANNEL, &id_cache))
124       channel = (SilcChannelEntry)id_cache->context;
125
126     /* Get sender Client ID */
127     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
128     if (!tmp)
129       goto out;
130
131     client_id = silc_id_payload_parse_id(tmp, tmp_len);
132     if (!client_id)
133       goto out;
134
135     /* Find Client entry and if not found query it */
136     client_entry = silc_client_get_client_by_id(client, conn, client_id);
137     if (!client_entry) {
138       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
139       goto out;
140     }
141
142     /* Get the channel name */
143     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
144     if (!tmp)
145       goto out;
146
147     /* Notify application */
148     client->ops->notify(client, conn, type, channel, tmp, client_entry);
149     break;
150
151   case SILC_NOTIFY_TYPE_JOIN:
152     /*
153      * Someone has joined to a channel. Get their ID and nickname and
154      * cache them for later use.
155      */
156
157     /* Get Client ID */
158     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
159     if (!tmp)
160       goto out;
161
162     client_id = silc_id_payload_parse_id(tmp, tmp_len);
163     if (!client_id)
164       goto out;
165
166     /* Find Client entry and if not found query it */
167     client_entry = silc_client_get_client_by_id(client, conn, client_id);
168     if (!client_entry) {
169       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
170       goto out;
171     }
172
173     /* If nickname or username hasn't been resolved, do so */
174     if (!client_entry->nickname || !client_entry->username) {
175       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
176       goto out;
177     }
178
179     /* Get Channel ID */
180     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
181     if (!tmp)
182       goto out;
183
184     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
185     if (!channel_id)
186       goto out;
187
188     /* Get channel entry */
189     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
190                                      SILC_ID_CHANNEL, &id_cache))
191       break;
192
193     channel = (SilcChannelEntry)id_cache->context;
194
195     /* Add client to channel */
196     if (client_entry != conn->local_entry) {
197       chu = silc_calloc(1, sizeof(*chu));
198       chu->client = client_entry;
199       silc_list_add(channel->clients, chu);
200     }
201
202     /* XXX add support for multiple same nicks on same channel. Check
203        for them here */
204
205     /* Notify application. The channel entry is sent last as this notify
206        is for channel but application don't know it from the arguments
207        sent by server. */
208     client->ops->notify(client, conn, type, client_entry, channel);
209     break;
210
211   case SILC_NOTIFY_TYPE_LEAVE:
212     /*
213      * Someone has left a channel. We will remove it from the channel but
214      * we'll keep it in the cache in case we'll need it later.
215      */
216     
217     /* Get Client ID */
218     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
219     if (!tmp)
220       goto out;
221
222     client_id = silc_id_payload_parse_id(tmp, tmp_len);
223     if (!client_id)
224       goto out;
225
226     /* Find Client entry */
227     client_entry = 
228       silc_client_get_client_by_id(client, conn, client_id);
229     if (!client_entry)
230       goto out;
231
232     /* Get channel entry */
233     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
234                                 SILC_ID_CHANNEL);
235     if (!channel_id)
236       goto out;
237     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
238                                      SILC_ID_CHANNEL, &id_cache))
239       break;
240
241     channel = (SilcChannelEntry)id_cache->context;
242
243     /* Remove client from channel */
244     silc_list_start(channel->clients);
245     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
246       if (chu->client == client_entry) {
247         silc_list_del(channel->clients, chu);
248         silc_free(chu);
249         break;
250       }
251     }
252
253     /* Notify application. The channel entry is sent last as this notify
254        is for channel but application don't know it from the arguments
255        sent by server. */
256     client->ops->notify(client, conn, type, client_entry, channel);
257     break;
258
259   case SILC_NOTIFY_TYPE_SIGNOFF:
260     /*
261      * Someone left SILC. We'll remove it from all channels and from cache.
262      */
263
264     /* Get Client ID */
265     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
266     if (!tmp)
267       goto out;
268
269     client_id = silc_id_payload_parse_id(tmp, tmp_len);
270     if (!client_id)
271       goto out;
272
273     /* Find Client entry */
274     client_entry = 
275       silc_client_get_client_by_id(client, conn, client_id);
276     if (!client_entry)
277       goto out;
278
279     /* Remove from all channels */
280     silc_client_remove_from_channels(client, conn, client_entry);
281
282     /* Remove from cache */
283     silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, 
284                            client_entry->id);
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                                      SILC_ID_CHANNEL, &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_id(conn->client_cache, SILC_ID_CLIENT, 
394                            client_entry->id);
395
396     /* Replace old ID entry with new one on all channels. */
397     silc_client_replace_from_channels(client, conn, client_entry,
398                                       client_entry2);
399
400     /* Notify application */
401     client->ops->notify(client, conn, type, client_entry, client_entry2);
402
403     /* Free data */
404     if (client_entry->nickname)
405       silc_free(client_entry->nickname);
406     if (client_entry->server)
407       silc_free(client_entry->server);
408     if (client_entry->id)
409       silc_free(client_entry->id);
410     if (client_entry->send_key)
411       silc_cipher_free(client_entry->send_key);
412     if (client_entry->receive_key)
413       silc_cipher_free(client_entry->receive_key);
414     silc_free(client_entry);
415     break;
416
417   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
418     /*
419      * Someone changed a channel mode
420      */
421
422     /* Get Client ID */
423     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
424     if (!tmp)
425       goto out;
426
427     idp = silc_id_payload_parse_data(tmp, tmp_len);
428     if (!idp)
429       goto out;
430
431     /* Find Client entry */
432     if (silc_id_payload_get_type(idp) == SILC_ID_CLIENT) {
433       client_id = silc_id_payload_parse_id(tmp, tmp_len);
434       if (!client_id) {
435         silc_id_payload_free(idp);
436         goto out;
437       }
438
439       client_entry = silc_client_get_client_by_id(client, conn, client_id);
440       if (!client_entry) {
441         silc_id_payload_free(idp);
442         goto out;
443       }
444     } else {
445       client_entry = NULL;
446     }
447
448     silc_id_payload_free(idp);
449
450     /* Get the mode */
451     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
452     if (!tmp)
453       goto out;
454
455     SILC_GET32_MSB(mode, tmp);
456
457     /* Get channel entry */
458     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
459                                 SILC_ID_CHANNEL);
460     if (!channel_id)
461       goto out;
462     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
463                                      SILC_ID_CHANNEL, &id_cache))
464       break;
465
466     channel = (SilcChannelEntry)id_cache->context;
467
468     /* Save the new mode */
469     channel->mode = mode;
470
471     /* Get the hmac */
472     tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
473     if (tmp) {
474       unsigned char hash[32];
475
476       if (channel->hmac)
477         silc_hmac_free(channel->hmac);
478       if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
479         goto out;
480
481       silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8,
482                      hash);
483       silc_hmac_set_key(channel->hmac, hash, 
484                         silc_hash_len(channel->hmac->hash));
485       memset(hash, 0, sizeof(hash));
486     }
487
488     /* Notify application. The channel entry is sent last as this notify
489        is for channel but application don't know it from the arguments
490        sent by server. */
491     client->ops->notify(client, conn, type, client_entry, mode, NULL, 
492                         tmp, channel);
493     break;
494
495   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
496     /*
497      * Someone changed user's mode on a channel
498      */
499
500     /* Get Client ID */
501     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
502     if (!tmp)
503       goto out;
504
505     client_id = silc_id_payload_parse_id(tmp, tmp_len);
506     if (!client_id)
507       goto out;
508
509     /* Find Client entry */
510     client_entry = 
511       silc_client_get_client_by_id(client, conn, client_id);
512     if (!client_entry)
513       goto out;
514
515     /* Get the mode */
516     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
517     if (!tmp)
518       goto out;
519
520     SILC_GET32_MSB(mode, tmp);
521
522     /* Get target Client ID */
523     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
524     if (!tmp)
525       goto out;
526
527     silc_free(client_id);
528     client_id = silc_id_payload_parse_id(tmp, tmp_len);
529     if (!client_id)
530       goto out;
531
532     /* Find target Client entry */
533     client_entry2 = 
534       silc_client_get_client_by_id(client, conn, client_id);
535     if (!client_entry2)
536       goto out;
537
538     /* Get channel entry */
539     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
540                                 SILC_ID_CHANNEL);
541     if (!channel_id)
542       goto out;
543     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
544                                      SILC_ID_CHANNEL, &id_cache))
545       break;
546
547     channel = (SilcChannelEntry)id_cache->context;
548
549     /* Save the mode */
550     silc_list_start(channel->clients);
551     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
552       if (chu->client == client_entry) {
553         chu->mode = mode;
554         break;
555       }
556     }
557
558     /* Notify application. The channel entry is sent last as this notify
559        is for channel but application don't know it from the arguments
560        sent by server. */
561     client->ops->notify(client, conn, type, client_entry, mode, 
562                         client_entry2, channel);
563     break;
564
565   case SILC_NOTIFY_TYPE_MOTD:
566     /*
567      * Received Message of the day
568      */
569
570     /* Get motd */
571     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
572     if (!tmp)
573       goto out;
574     
575     /* Notify application */
576     client->ops->notify(client, conn, type, tmp);
577     break;
578
579   case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
580     /*
581      * Router has enforced a new ID to a channel. Let's change the old
582      * ID to the one provided here.
583      */
584
585     /* Get the old ID */
586     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
587     if (!tmp)
588       goto out;
589     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
590     if (!channel_id)
591       goto out;
592     
593     /* Get the channel entry */
594     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
595                                      SILC_ID_CHANNEL, &id_cache))
596       break;
597
598     channel = (SilcChannelEntry)id_cache->context;
599
600     /* Free the old ID */
601     silc_free(channel->id);
602
603     /* Get the new ID */
604     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
605     if (!tmp)
606       goto out;
607     channel->id = silc_id_payload_parse_id(tmp, tmp_len);
608     if (!channel->id)
609       goto out;
610
611     id_cache->id = (void *)channel->id;
612
613     /* Notify application */
614     client->ops->notify(client, conn, type, channel, channel);
615     break;
616
617   case SILC_NOTIFY_TYPE_KICKED:
618     /*
619      * A client (maybe me) was kicked from a channel
620      */
621
622     /* Get Client ID */
623     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
624     if (!tmp)
625       goto out;
626
627     client_id = silc_id_payload_parse_id(tmp, tmp_len);
628     if (!client_id)
629       goto out;
630
631     /* Find Client entry */
632     client_entry = silc_client_get_client_by_id(client, conn, client_id);
633     if (!client_entry)
634       goto out;
635
636     /* Get channel entry */
637     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
638                                 SILC_ID_CHANNEL);
639     if (!channel_id)
640       goto out;
641     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
642                                      SILC_ID_CHANNEL, &id_cache))
643       break;
644
645     channel = (SilcChannelEntry)id_cache->context;
646
647     /* Get comment */
648     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
649
650     /* Notify application. The channel entry is sent last as this notify
651        is for channel but application don't know it from the arguments
652        sent by server. */
653     client->ops->notify(client, conn, type, client_entry, tmp, channel);
654
655     /* If I was kicked from channel, remove the channel */
656     if (client_entry == conn->local_entry) {
657       if (conn->current_channel == channel)
658         conn->current_channel = NULL;
659       silc_idcache_del_by_id(conn->channel_cache, 
660                              SILC_ID_CHANNEL, channel->id);
661       silc_free(channel->channel_name);
662       silc_free(channel->id);
663       silc_free(channel->key);
664       silc_cipher_free(channel->channel_key);
665       silc_free(channel);
666     }
667     break;
668
669   case SILC_NOTIFY_TYPE_KILLED:
670     /*
671      * A client (maybe me) was killed from the network.
672      */
673
674     /* Get Client ID */
675     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
676     if (!tmp)
677       goto out;
678
679     client_id = silc_id_payload_parse_id(tmp, tmp_len);
680     if (!client_id)
681       goto out;
682
683     /* Find Client entry */
684     client_entry = silc_client_get_client_by_id(client, conn, client_id);
685     if (!client_entry)
686       goto out;
687
688     /* Get comment */
689     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
690
691     /* Notify application. */
692     client->ops->notify(client, conn, type, client_entry, tmp);
693
694     if (client_entry != conn->local_entry) {
695       /* Remove client from all channels */
696       silc_client_remove_from_channels(client, conn, client_entry);
697       silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, 
698                              client_entry->id);
699       if (client_entry->nickname)
700         silc_free(client_entry->nickname);
701       if (client_entry->server)
702         silc_free(client_entry->server);
703       if (client_entry->id)
704         silc_free(client_entry->id);
705       if (client_entry->send_key)
706         silc_cipher_free(client_entry->send_key);
707       if (client_entry->receive_key)
708         silc_cipher_free(client_entry->receive_key);
709       silc_free(client_entry);
710     }
711
712     break;
713     
714   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
715     {
716       /*
717        * A server quit the SILC network and some clients must be removed
718        * from channels as they quit as well.
719        */
720       SilcClientEntry *clients = NULL;
721       uint32 clients_count = 0;
722       int i;
723
724       for (i = 1; i < silc_argument_get_arg_num(args); i++) {
725         /* Get Client ID */
726         tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
727         if (tmp) {
728           client_id = silc_id_payload_parse_id(tmp, tmp_len);
729           if (!client_id)
730             goto out;
731           
732           /* Get the client entry */
733           client_entry = silc_client_get_client_by_id(client, conn, client_id);
734           if (client_entry) {
735             clients = silc_realloc(clients, sizeof(*clients) * 
736                                    (clients_count + 1));
737             clients[clients_count] = client_entry;
738             clients_count++;
739           }
740           silc_free(client_id);
741         }
742       }
743       client_id = NULL;
744
745       /* Notify application. We don't keep server entries so the server
746          entry is returned as NULL. The client's are returned as array
747          of SilcClientEntry pointers. */
748       client->ops->notify(client, conn, type, NULL, clients, clients_count);
749
750       for (i = 0; i < clients_count; i++) {
751         /* Remove client from all channels */
752         client_entry = clients[i];
753         if (client_entry == conn->local_entry)
754           continue;
755
756         silc_client_remove_from_channels(client, conn, client_entry);
757         silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, 
758                                client_entry->id);
759         if (client_entry->nickname)
760           silc_free(client_entry->nickname);
761         if (client_entry->server)
762           silc_free(client_entry->server);
763         if (client_entry->id)
764           silc_free(client_entry->id);
765         if (client_entry->send_key)
766           silc_cipher_free(client_entry->send_key);
767         if (client_entry->receive_key)
768           silc_cipher_free(client_entry->receive_key);
769         silc_free(client_entry);
770       }
771       silc_free(clients);
772
773     }
774     break;
775
776   default:
777     break;
778   }
779
780  out:
781   silc_notify_payload_free(payload);
782   if (client_id)
783     silc_free(client_id);
784   if (channel_id)
785     silc_free(channel_id);
786 }