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