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