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