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