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