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