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