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