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