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