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