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