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