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