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