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