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