Merged from silc_1_0_branch.
[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   SilcClient client = res->context;
39   SilcClientConnection conn = res->sock->user_data;
40   SilcClientID *client_id = res->packet;
41   silc_client_get_client_by_id_resolve(client, conn, client_id,
42                                        NULL, NULL, NULL);
43   silc_free(client_id);
44   silc_socket_free(res->sock);
45   silc_free(res);
46 }
47
48 SILC_TASK_CALLBACK(silc_client_notify_del_client_cb)
49 {
50   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
51   SilcClient client = res->context;
52   SilcClientConnection conn = res->sock->user_data;
53   SilcClientID *client_id = res->packet;
54   SilcClientEntry client_entry;
55   client_entry = silc_client_get_client_by_id(client, conn, client_id);
56   if (client_entry)
57     silc_client_del_client(client, conn, client_entry);
58   silc_free(client_id);
59   silc_socket_free(res->sock);
60   silc_free(res);
61 }
62
63 /* Called when notify is received and some async operation (such as command)
64    is required before processing the notify message. This calls again the
65    silc_client_notify_by_server and reprocesses the original notify packet. */
66
67 static void silc_client_notify_by_server_pending(void *context, void *context2)
68 {
69   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
70   SilcClientCommandReplyContext reply = 
71     (SilcClientCommandReplyContext)context2;
72
73   SILC_LOG_DEBUG(("Start"));
74
75   if (reply && !silc_command_get_status(reply->payload, NULL, NULL))
76     goto out;
77
78   silc_client_notify_by_server(res->context, res->sock, res->packet);
79
80  out:
81   silc_socket_free(res->sock);
82   silc_packet_context_free(res->packet);
83   silc_free(res);
84 }
85
86 /* Resets the channel entry's resolve_cmd_ident after whatever-thing
87    was resolved is completed. */
88
89 static void silc_client_channel_cond(void *context, void *context2)
90 {
91   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
92   SilcClient client = res->context;
93   SilcClientConnection conn = res->sock->user_data;
94   SilcChannelID *channel_id = res->packet;
95   SilcChannelEntry channel;
96   channel = silc_client_get_channel_by_id(client, conn, channel_id);
97   if (channel)
98     channel->resolve_cmd_ident = 0;
99   silc_free(channel_id);
100   silc_socket_free(res->sock);
101   silc_free(res);
102 }
103
104 /* Function that starts waiting for the `cmd_ident' to arrive and
105    marks the channel info being resolved.  */
106
107 static void silc_client_channel_set_wait(SilcClient client,
108                                          SilcClientConnection conn,
109                                          SilcChannelEntry channel,
110                                          SilcUInt16 cmd_ident)
111 {
112   SilcClientNotifyResolve res;
113
114   if (!channel->resolve_cmd_ident) {
115     res = silc_calloc(1, sizeof(*res));
116     res->context = client;
117     res->sock = silc_socket_dup(conn->sock);
118     res->packet = silc_id_dup(channel->id, SILC_ID_CHANNEL);
119     silc_client_command_pending(conn, SILC_COMMAND_NONE, cmd_ident,
120                                 silc_client_channel_cond, res);
121     channel->resolve_cmd_ident = cmd_ident;
122   }
123 }
124
125 /* Attaches to the channel's resolving cmd ident and calls the 
126    notify handling with `packet' after it's received. */
127
128 static void silc_client_channel_wait(SilcClient client,
129                                      SilcClientConnection conn,
130                                      SilcChannelEntry channel,
131                                      SilcPacketContext *packet)
132 {
133   SilcClientNotifyResolve res;
134
135   if (!channel->resolve_cmd_ident)
136     return;
137
138   res = silc_calloc(1, sizeof(*res));
139   res->packet = silc_packet_context_dup(packet);
140   res->context = client;
141   res->sock = silc_socket_dup(conn->sock);
142
143   silc_client_command_pending(conn, SILC_COMMAND_NONE,
144                               channel->resolve_cmd_ident,
145                               silc_client_notify_by_server_pending, res);
146 }
147
148 /* Resolve client, channel or server information. */
149
150 static void silc_client_notify_by_server_resolve(SilcClient client,
151                                                  SilcClientConnection conn,
152                                                  SilcPacketContext *packet,
153                                                  SilcIdType id_type,
154                                                  void *id)
155 {
156   SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
157   SilcBuffer idp = silc_id_payload_encode(id, id_type);
158
159   res->packet = silc_packet_context_dup(packet);
160   res->context = client;
161   res->sock = silc_socket_dup(conn->sock);
162
163   /* For client resolving use WHOIS, and otherwise use IDENTIFY */
164   if (id_type == SILC_ID_CLIENT) {
165     silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
166                                  silc_client_command_reply_whois_i, 0,
167                                  ++conn->cmd_ident);
168     silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
169                              1, 4, idp->data, idp->len);
170     silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
171                                 silc_client_notify_by_server_pending, res);
172   } else {
173     silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
174                                  silc_client_command_reply_identify_i, 0,
175                                  ++conn->cmd_ident);
176     silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, 
177                              conn->cmd_ident, 1, 5, idp->data, idp->len);
178     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
179                                 silc_client_notify_by_server_pending, res);
180   }
181   silc_buffer_free(idp);
182 }
183
184 /* Received notify message from server */
185
186 void silc_client_notify_by_server(SilcClient client,
187                                   SilcSocketConnection sock,
188                                   SilcPacketContext *packet)
189 {
190   SilcBuffer buffer = packet->buffer;
191   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
192   SilcNotifyPayload payload;
193   SilcNotifyType type;
194   SilcArgumentPayload args;
195
196   void *id;
197   SilcIdType id_type;
198   SilcClientID *client_id = NULL;
199   SilcChannelID *channel_id = NULL;
200   SilcServerID *server_id = NULL;
201   SilcClientEntry client_entry = NULL;
202   SilcClientEntry client_entry2 = NULL;
203   SilcChannelEntry channel;
204   SilcChannelUser chu;
205   SilcServerEntry server;
206   unsigned char *tmp;
207   SilcUInt32 tmp_len, mode;
208
209   SILC_LOG_DEBUG(("Start"));
210
211   payload = silc_notify_payload_parse(buffer->data, buffer->len);
212   if (!payload)
213     goto out;
214
215   type = silc_notify_get_type(payload);
216   args = silc_notify_get_args(payload);
217   if (!args)
218     goto out;
219
220   switch(type) {
221   case SILC_NOTIFY_TYPE_NONE:
222     /* Notify application */
223     client->internal->ops->notify(client, conn, type, 
224                                   silc_argument_get_arg_type(args, 1, NULL));
225     break;
226
227   case SILC_NOTIFY_TYPE_INVITE:
228     /* 
229      * Someone invited me to a channel. Find Client and Channel entries
230      * for the application.
231      */
232     
233     SILC_LOG_DEBUG(("Notify: INVITE"));
234
235     /* Get Channel ID */
236     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
237     if (!tmp)
238       goto out;
239
240     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
241     if (!channel_id)
242       goto out;
243
244     /* Get the channel entry */
245     channel = silc_client_get_channel_by_id(client, conn, channel_id);
246
247     /* Get sender Client ID */
248     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
249     if (!tmp)
250       goto out;
251
252     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
253     if (!client_id)
254       goto out;
255
256     /* Find Client entry and if not found query it */
257     client_entry = silc_client_get_client_by_id(client, conn, client_id);
258     if (!client_entry) {
259       silc_client_notify_by_server_resolve(client, conn, packet, 
260                                            SILC_ID_CLIENT, client_id);
261       goto out;
262     }
263
264     /* Get the channel name */
265     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
266     if (!tmp)
267       goto out;
268
269     /* Notify application */
270     client->internal->ops->notify(client, conn, type, channel, tmp, 
271                                   client_entry);
272     break;
273
274   case SILC_NOTIFY_TYPE_JOIN:
275     /*
276      * Someone has joined to a channel. Get their ID and nickname and
277      * cache them for later use.
278      */
279
280     SILC_LOG_DEBUG(("Notify: JOIN"));
281
282     /* Get Client ID */
283     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
284     if (!tmp)
285       goto out;
286
287     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
288     if (!client_id)
289       goto out;
290
291     /* Find Client entry and if not found query it */
292     client_entry = silc_client_get_client_by_id(client, conn, client_id);
293     if (!client_entry) {
294       silc_client_notify_by_server_resolve(client, conn, packet, 
295                                            SILC_ID_CLIENT, client_id);
296       goto out;
297     }
298
299     /* If nickname or username hasn't been resolved, do so */
300     if (!client_entry->nickname || !client_entry->username) {
301       if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
302         client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
303         goto out;
304       }
305       silc_client_notify_by_server_resolve(client, conn, packet, 
306                                            SILC_ID_CLIENT, client_id);
307       client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
308       client_entry->resolve_cmd_ident = conn->cmd_ident;
309       goto out;
310     } else {
311       if (client_entry != conn->local_entry)
312         silc_client_nickname_format(client, conn, client_entry);
313     }
314
315     /* Get Channel ID */
316     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
317     if (!tmp)
318       goto out;
319
320     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
321     if (!channel_id)
322       goto out;
323
324     /* Get channel entry */
325     channel = silc_client_get_channel_by_id(client, conn, channel_id);
326     if (!channel)
327       break;
328
329     /* Join the client to channel */
330     if (!silc_client_on_channel(channel, client_entry)) {
331       chu = silc_calloc(1, sizeof(*chu));
332       chu->client = client_entry;
333       chu->channel = channel;
334       silc_hash_table_add(channel->user_list, client_entry, chu);
335       silc_hash_table_add(client_entry->channels, channel, chu);
336     }
337
338     /* Notify application. The channel entry is sent last as this notify
339        is for channel but application don't know it from the arguments
340        sent by server. */
341     client->internal->ops->notify(client, conn, type, client_entry, channel);
342     break;
343
344   case SILC_NOTIFY_TYPE_LEAVE:
345     /*
346      * Someone has left a channel. We will remove it from the channel but
347      * we'll keep it in the cache in case we'll need it later.
348      */
349     
350     SILC_LOG_DEBUG(("Notify: LEAVE"));
351
352     /* Get Client ID */
353     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
354     if (!tmp)
355       goto out;
356
357     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
358     if (!client_id)
359       goto out;
360
361     /* Find Client entry */
362     client_entry = 
363       silc_client_get_client_by_id(client, conn, client_id);
364     if (!client_entry)
365       goto out;
366
367     /* Get channel entry */
368     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
369                                 SILC_ID_CHANNEL);
370     if (!channel_id)
371       goto out;
372     channel = silc_client_get_channel_by_id(client, conn, channel_id);
373     if (!channel)
374       break;
375
376     /* Remove client from channel */
377     chu = silc_client_on_channel(channel, client_entry);
378     if (chu) {
379       silc_hash_table_del(client_entry->channels, channel);
380       silc_hash_table_del(channel->user_list, client_entry);
381       silc_free(chu);
382     }
383
384     /* Some client implementations actually quit network by first doing
385        LEAVE and then immediately SIGNOFF.  We'll check for this by doing 
386        check for the client after 5 - 34 seconds.  If it is not valid after
387        that we'll remove the client from cache. */
388     if (!silc_hash_table_count(client_entry->channels)) {
389       SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
390       res->context = client;
391       res->sock = silc_socket_dup(conn->sock);
392       res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
393       silc_schedule_task_add(client->schedule, conn->sock->sock,
394                              silc_client_notify_check_client, res,
395                              (5 + (silc_rng_get_rn16(client->rng) % 29)),
396                              0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
397     }
398
399     /* Notify application. The channel entry is sent last as this notify
400        is for channel but application don't know it from the arguments
401        sent by server. */
402     client->internal->ops->notify(client, conn, type, client_entry, channel);
403     break;
404
405   case SILC_NOTIFY_TYPE_SIGNOFF:
406     /*
407      * Someone left SILC. We'll remove it from all channels and from cache.
408      */
409
410     SILC_LOG_DEBUG(("Notify: SIGNOFF"));
411
412     /* Get Client ID */
413     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
414     if (!tmp)
415       goto out;
416
417     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
418     if (!client_id)
419       goto out;
420
421     /* Find Client entry */
422     client_entry = 
423       silc_client_get_client_by_id(client, conn, client_id);
424     if (!client_entry)
425       goto out;
426
427     /* Remove from all channels */
428     silc_client_remove_from_channels(client, conn, client_entry);
429
430     /* Remove from cache */
431     silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
432
433     /* Get signoff message */
434     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
435     if (tmp_len > 128)
436       tmp = NULL;
437
438     /* Notify application */
439     client->internal->ops->notify(client, conn, type, client_entry, tmp);
440
441     /* Free data */
442     silc_client_del_client_entry(client, conn, client_entry);
443     break;
444
445   case SILC_NOTIFY_TYPE_TOPIC_SET:
446     /*
447      * Someone set the topic on a channel.
448      */
449
450     SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
451
452     /* Get channel entry */
453     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
454                                 SILC_ID_CHANNEL);
455     if (!channel_id)
456       goto out;
457     channel = silc_client_get_channel_by_id(client, conn, channel_id);
458     if (!channel)
459       break;
460
461     /* Get ID */
462     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
463     if (!tmp)
464       goto out;
465     id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
466     if (!id)
467       goto out;
468
469     /* Find Client entry */
470     if (id_type == SILC_ID_CLIENT) {
471       /* Find Client entry */
472       client_id = id;
473       client_entry = silc_client_get_client_by_id(client, conn, client_id);
474       if (!client_entry) {
475         silc_client_channel_set_wait(client, conn, channel,
476                                      conn->cmd_ident + 1);
477         silc_client_notify_by_server_resolve(client, conn, packet, 
478                                              SILC_ID_CLIENT, client_id);
479         goto out;
480       }
481     } else if (id_type == SILC_ID_SERVER) {
482       /* Find Server entry */
483       server_id = id;
484       server = silc_client_get_server_by_id(client, conn, server_id);
485       if (!server) {
486         silc_client_channel_set_wait(client, conn, channel,
487                                      conn->cmd_ident + 1);
488         silc_client_notify_by_server_resolve(client, conn, packet, 
489                                              SILC_ID_SERVER, server_id);
490         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
491         if (!server)
492           goto out;
493
494         server->resolve_cmd_ident = conn->cmd_ident;
495         server_id = NULL;
496         goto out;
497       }
498
499       /* If entry being resoled, wait for it before processing this notify */
500       if (server->resolve_cmd_ident) {
501         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
502         res->packet = silc_packet_context_dup(packet);
503         res->context = client;
504         res->sock = silc_socket_dup(conn->sock);
505         silc_client_command_pending(conn, SILC_COMMAND_NONE, 
506                                     server->resolve_cmd_ident,
507                                     silc_client_notify_by_server_pending, res);
508         goto out;
509       }
510       
511       /* Save the pointer to the client_entry pointer */
512       client_entry = (SilcClientEntry)server;
513     } else {
514       /* Find Channel entry */
515       silc_free(channel_id);
516       channel_id = id;
517       client_entry = (SilcClientEntry)
518         silc_client_get_channel_by_id(client, conn, channel_id);
519       if (!client_entry) {
520         silc_client_channel_set_wait(client, conn, channel,
521                                      conn->cmd_ident + 1);
522         silc_client_notify_by_server_resolve(client, conn, packet, 
523                                              SILC_ID_CHANNEL, channel_id);
524         goto out;
525       }
526     }
527
528     /* Get topic */
529     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
530     if (!tmp)
531       goto out;
532
533     /* If information is being resolved for this channel, wait for it */
534     if (channel->resolve_cmd_ident) {
535       silc_client_channel_wait(client, conn, channel, packet);
536       goto out;
537     }
538
539     /* Notify application. The channel entry is sent last as this notify
540        is for channel but application don't know it from the arguments
541        sent by server. */
542     client->internal->ops->notify(client, conn, type, id_type,
543                                   client_entry, tmp, channel);
544
545     break;
546
547   case SILC_NOTIFY_TYPE_NICK_CHANGE:
548     /*
549      * Someone changed their nickname. If we don't have entry for the new
550      * ID we will query it and return here after it's done. After we've
551      * returned we fetch the old entry and free it and notify the 
552      * application.
553      */
554
555     SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
556
557     /* Get old Client ID */
558     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
559     if (!tmp)
560       goto out;
561
562     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
563     if (!client_id)
564       goto out;
565
566     /* Ignore my ID */
567     if (conn->local_id && SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
568       break;
569
570     /* Find old Client entry */
571     client_entry = silc_client_get_client_by_id(client, conn, client_id);
572     if (!client_entry)
573       goto out;
574     silc_free(client_id);
575     client_id = NULL;
576
577     /* Wait for resolving if necessary */
578     if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
579       SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
580       res->packet = silc_packet_context_dup(packet);
581       res->context = client;
582       res->sock = silc_socket_dup(conn->sock);
583       silc_client_command_pending(conn, SILC_COMMAND_NONE, 
584                                   client_entry->resolve_cmd_ident,
585                                   silc_client_notify_by_server_pending, res);
586       goto out;
587     }
588
589     client_entry->valid = FALSE;
590
591     /* Get new Client ID */
592     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
593     if (!tmp)
594       goto out;
595
596     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
597     if (!client_id)
598       goto out;
599
600     /* Take the nickname */
601     tmp = silc_argument_get_arg_type(args, 3, NULL);
602     if (!tmp)
603       goto out;
604
605     /* Check whether nickname changed at all.  It is possible that nick
606        change notify is received but nickname didn't changed, only the
607        ID changes.  Check whether the hashes in the Client ID match, if
608        they do nickname didn't change. */
609     if (SILC_ID_COMPARE_HASH(client_entry->id, client_id)) {
610       /* Nickname didn't change. Update only the ID */
611       silc_idcache_del_by_context(conn->internal->client_cache,
612                                   client_entry);
613       silc_free(client_entry->id);
614       client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
615       silc_idcache_add(conn->internal->client_cache, strdup(tmp),
616                        client_entry->id, client_entry, 0, NULL);
617
618       /* Notify application */
619       client->internal->ops->notify(client, conn, type, 
620                                     client_entry, client_entry);
621       break;
622     }
623
624     /* Create new client entry, and save all old information with the
625        new nickname and client ID */
626     client_entry2 = silc_client_add_client(client, conn, NULL, NULL, 
627                                            client_entry->realname,
628                                            silc_id_dup(client_id, 
629                                                        SILC_ID_CLIENT), 0);
630     if (!client_entry2)
631       goto out;
632
633     if (client_entry->server)
634       client_entry2->server = strdup(client_entry->server);
635     if (client_entry->username)
636       client_entry2->username = strdup(client_entry->username);
637     if (client_entry->hostname)
638       client_entry2->hostname = strdup(client_entry->hostname);
639     client_entry2->fingerprint = client_entry->fingerprint;
640     client_entry2->fingerprint_len = client_entry->fingerprint_len;
641     client_entry->fingerprint = NULL;
642     client_entry->fingerprint_len = NULL;
643     silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
644                               client_entry->mode);
645
646     /* Remove the old from cache */
647     silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
648     
649     /* Replace old ID entry with new one on all channels. */
650     silc_client_replace_from_channels(client, conn, client_entry,
651                                       client_entry2);
652
653     /* Notify application */
654     client->internal->ops->notify(client, conn, type, 
655                                   client_entry, client_entry2);
656     
657     /* Free old client entry */
658     silc_client_del_client_entry(client, conn, client_entry);
659
660     break;
661
662   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
663     /*
664      * Someone changed a channel mode
665      */
666
667     SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
668
669     /* Get channel entry */
670     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
671                                 SILC_ID_CHANNEL);
672     if (!channel_id)
673       goto out;
674     channel = silc_client_get_channel_by_id(client, conn, channel_id);
675     if (!channel)
676       goto out;
677
678     /* Get ID */
679     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
680     if (!tmp)
681       goto out;
682     id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
683     if (!id)
684       goto out;
685
686     /* Find Client entry */
687     if (id_type == SILC_ID_CLIENT) {
688       /* Find Client entry */
689       client_id = id;
690       client_entry = silc_client_get_client_by_id(client, conn, client_id);
691       if (!client_entry) {
692         silc_client_channel_set_wait(client, conn, channel,
693                                      conn->cmd_ident + 1);
694         silc_client_notify_by_server_resolve(client, conn, packet, 
695                                              SILC_ID_CLIENT, client_id);
696         goto out;
697       }
698
699       if (!client_entry->nickname) {
700         if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
701           /* Attach to existing resolving */
702           SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
703           res->packet = silc_packet_context_dup(packet);
704           res->context = client;
705           res->sock = silc_socket_dup(conn->sock);
706           silc_client_command_pending(conn, SILC_COMMAND_NONE, 
707                                       client_entry->resolve_cmd_ident,
708                                       silc_client_notify_by_server_pending,
709                                       res);
710           goto out;
711         }
712
713         /* Do new resolving */
714         silc_client_channel_set_wait(client, conn, channel,
715                                      conn->cmd_ident + 1);
716         silc_client_notify_by_server_resolve(client, conn, packet, 
717                                              SILC_ID_CLIENT, client_id);
718         goto out;
719       }
720     } else if (id_type == SILC_ID_SERVER) {
721       /* Find Server entry */
722       server_id = id;
723       server = silc_client_get_server_by_id(client, conn, server_id);
724       if (!server) {
725         silc_client_channel_set_wait(client, conn, channel,
726                                      conn->cmd_ident + 1);
727         silc_client_notify_by_server_resolve(client, conn, packet, 
728                                              SILC_ID_SERVER, server_id);
729         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
730         if (!server)
731           goto out;
732
733         server->resolve_cmd_ident = conn->cmd_ident;
734         server_id = NULL;
735         goto out;
736       }
737
738       /* If entry being resoled, wait for it before processing this notify */
739       if (server->resolve_cmd_ident) {
740         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
741         res->packet = silc_packet_context_dup(packet);
742         res->context = client;
743         res->sock = silc_socket_dup(conn->sock);
744         silc_client_command_pending(conn, SILC_COMMAND_NONE, 
745                                     server->resolve_cmd_ident,
746                                     silc_client_notify_by_server_pending, res);
747         goto out;
748       }
749       
750       /* Save the pointer to the client_entry pointer */
751       client_entry = (SilcClientEntry)server;
752     } else {
753       /* Find Channel entry */
754       silc_free(channel_id);
755       channel_id = id;
756       client_entry = (SilcClientEntry)
757         silc_client_get_channel_by_id(client, conn, channel_id);
758       if (!client_entry) {
759         silc_client_channel_set_wait(client, conn, channel,
760                                      conn->cmd_ident + 1);
761         silc_client_notify_by_server_resolve(client, conn, packet, 
762                                              SILC_ID_CHANNEL, channel_id);
763         goto out;
764       }
765     }
766
767     /* Get the mode */
768     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
769     if (!tmp)
770       goto out;
771
772     SILC_GET32_MSB(mode, tmp);
773
774     /* If information is being resolved for this channel, wait for it */
775     if (channel->resolve_cmd_ident) {
776       silc_client_channel_wait(client, conn, channel, packet);
777       goto out;
778     }
779
780     /* Save the new mode */
781     channel->mode = mode;
782
783     /* Get the hmac */
784     tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
785     if (tmp) {
786       unsigned char hash[32];
787
788       if (channel->hmac)
789         silc_hmac_free(channel->hmac);
790       if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
791         goto out;
792
793       silc_hash_make(silc_hmac_get_hash(channel->hmac), 
794                      channel->key, channel->key_len / 8,
795                      hash);
796       silc_hmac_set_key(channel->hmac, hash, 
797                         silc_hash_len(silc_hmac_get_hash(channel->hmac)));
798       memset(hash, 0, sizeof(hash));
799     }
800
801     /* Notify application. The channel entry is sent last as this notify
802        is for channel but application don't know it from the arguments
803        sent by server. */
804     client->internal->ops->notify(client, conn, type, id_type,
805                                   client_entry, mode, NULL, tmp, channel);
806     break;
807
808   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
809     /*
810      * Someone changed user's mode on a channel
811      */
812
813     SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
814
815     /* Get channel entry */
816     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
817                                 SILC_ID_CHANNEL);
818     if (!channel_id)
819       goto out;
820     channel = silc_client_get_channel_by_id(client, conn, channel_id);
821     if (!channel)
822       break;
823
824     /* Get ID */
825     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
826     if (!tmp)
827       goto out;
828     id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
829     if (!id)
830       goto out;
831
832     /* Find Client entry */
833     if (id_type == SILC_ID_CLIENT) {
834       /* Find Client entry */
835       client_id = id;
836       client_entry = silc_client_get_client_by_id(client, conn, client_id);
837       if (!client_entry) {
838         silc_client_channel_set_wait(client, conn, channel,
839                                      conn->cmd_ident + 1);
840         silc_client_notify_by_server_resolve(client, conn, packet, 
841                                              SILC_ID_CLIENT, client_id);
842         goto out;
843       }
844
845       if (!client_entry->nickname) {
846         if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
847           /* Attach to existing resolving */
848           SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
849           res->packet = silc_packet_context_dup(packet);
850           res->context = client;
851           res->sock = silc_socket_dup(conn->sock);
852           silc_client_command_pending(conn, SILC_COMMAND_NONE, 
853                                       client_entry->resolve_cmd_ident,
854                                       silc_client_notify_by_server_pending,
855                                       res);
856           goto out;
857         }
858
859         /* Do new resolving */
860         silc_client_channel_set_wait(client, conn, channel,
861                                      conn->cmd_ident + 1);
862         silc_client_notify_by_server_resolve(client, conn, packet, 
863                                              SILC_ID_CLIENT, client_id);
864         goto out;
865       }
866     } else if (id_type == SILC_ID_SERVER) {
867       /* Find Server entry */
868       server_id = id;
869       server = silc_client_get_server_by_id(client, conn, server_id);
870       if (!server) {
871         silc_client_channel_set_wait(client, conn, channel,
872                                      conn->cmd_ident + 1);
873         silc_client_notify_by_server_resolve(client, conn, packet, 
874                                              SILC_ID_SERVER, server_id);
875         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
876         if (!server)
877           goto out;
878
879         server->resolve_cmd_ident = conn->cmd_ident;
880         server_id = NULL;
881         goto out;
882       }
883
884       /* If entry being resoled, wait for it before processing this notify */
885       if (server->resolve_cmd_ident) {
886         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
887         res->packet = silc_packet_context_dup(packet);
888         res->context = client;
889         res->sock = silc_socket_dup(conn->sock);
890         silc_client_command_pending(conn, SILC_COMMAND_NONE, 
891                                     server->resolve_cmd_ident,
892                                     silc_client_notify_by_server_pending, res);
893         goto out;
894       }
895
896       /* Save the pointer to the client_entry pointer */
897       client_entry = (SilcClientEntry)server;
898     } else {
899       /* Find Channel entry */
900       silc_free(channel_id);
901       channel_id = id;
902       client_entry = (SilcClientEntry)
903         silc_client_get_channel_by_id(client, conn, channel_id);
904       if (!client_entry) {
905         silc_client_channel_set_wait(client, conn, channel,
906                                      conn->cmd_ident + 1);
907         silc_client_notify_by_server_resolve(client, conn, packet, 
908                                              SILC_ID_CHANNEL, channel_id);
909         goto out;
910       }
911     }
912
913     /* Get the mode */
914     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
915     if (!tmp)
916       goto out;
917
918     SILC_GET32_MSB(mode, tmp);
919
920     /* If information is being resolved for this channel, wait for it */
921     if (channel->resolve_cmd_ident) {
922       silc_client_channel_wait(client, conn, channel, packet);
923       goto out;
924     }
925
926     /* Get target Client ID */
927     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
928     if (!tmp)
929       goto out;
930
931     silc_free(client_id);
932     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
933     if (!client_id)
934       goto out;
935
936     /* Find target Client entry */
937     client_entry2 = 
938       silc_client_get_client_by_id(client, conn, client_id);
939     if (!client_entry2) {
940       silc_client_notify_by_server_resolve(client, conn, packet, 
941                                            SILC_ID_CLIENT, client_id);
942       goto out;
943     }
944
945     /* Save the mode */
946     chu = silc_client_on_channel(channel, client_entry2);
947     if (chu)
948       chu->mode = mode;
949
950     /* Notify application. The channel entry is sent last as this notify
951        is for channel but application don't know it from the arguments
952        sent by server. */
953     client->internal->ops->notify(client, conn, type,
954                                   id_type, client_entry, mode, 
955                                   client_entry2, channel);
956     break;
957
958   case SILC_NOTIFY_TYPE_MOTD:
959     /*
960      * Received Message of the day
961      */
962
963     SILC_LOG_DEBUG(("Notify: MOTD"));
964
965     /* Get motd */
966     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
967     if (!tmp)
968       goto out;
969     
970     /* Notify application */
971     client->internal->ops->notify(client, conn, type, tmp);
972     break;
973
974   case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
975     /*
976      * Router has enforced a new ID to a channel. Let's change the old
977      * ID to the one provided here.
978      */
979
980     SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
981
982     /* Get the old ID */
983     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
984     if (!tmp)
985       goto out;
986     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
987     if (!channel_id)
988       goto out;
989
990     /* Get the channel entry */
991     channel = silc_client_get_channel_by_id(client, conn, channel_id);
992     if (!channel)
993       goto out;
994
995     silc_free(channel_id);
996     channel_id = NULL;
997
998     /* Get the new ID */
999     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1000     if (!tmp)
1001       goto out;
1002     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1003     if (!channel_id)
1004       goto out;
1005
1006     /* Replace the Channel ID */
1007     if (silc_client_replace_channel_id(client, conn, channel, channel_id))
1008       channel_id = NULL;
1009
1010     /* Notify application */
1011     client->internal->ops->notify(client, conn, type, channel, channel);
1012     break;
1013
1014   case SILC_NOTIFY_TYPE_KICKED:
1015     /*
1016      * A client (maybe me) was kicked from a channel
1017      */
1018
1019     SILC_LOG_DEBUG(("Notify: KICKED"));
1020
1021     /* Get Client ID */
1022     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1023     if (!tmp)
1024       goto out;
1025
1026     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1027     if (!client_id)
1028       goto out;
1029
1030     /* Find Client entry */
1031     client_entry = silc_client_get_client_by_id(client, conn, client_id);
1032     if (!client_entry)
1033       goto out;
1034
1035     /* Get channel entry */
1036     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1037                                 SILC_ID_CHANNEL);
1038     if (!channel_id)
1039       goto out;
1040     channel = silc_client_get_channel_by_id(client, conn, channel_id);
1041     if (!channel)
1042       break;
1043
1044     /* From protocol version 1.1 we get the kicker's client ID as well */
1045     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1046     if (tmp) {
1047       silc_free(client_id);
1048       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1049       if (!client_id)
1050         goto out;
1051
1052       /* Find kicker's client entry and if not found resolve it */
1053       client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
1054       if (!client_entry2) {
1055         silc_client_notify_by_server_resolve(client, conn, packet, 
1056                                              SILC_ID_CLIENT, client_id);
1057         goto out;
1058       } else {
1059         if (client_entry2 != conn->local_entry)
1060           silc_client_nickname_format(client, conn, client_entry2);
1061       }
1062     }
1063
1064     /* Get comment */
1065     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1066
1067     /* Notify application. The channel entry is sent last as this notify
1068        is for channel but application don't know it from the arguments
1069        sent by server. */
1070     client->internal->ops->notify(client, conn, type, client_entry, tmp, 
1071                                   client_entry2, channel);
1072
1073     /* Remove kicked client from channel */
1074     if (client_entry == conn->local_entry) {
1075       /* If I was kicked from channel, remove the channel */
1076       if (conn->current_channel == channel)
1077         conn->current_channel = NULL;
1078       silc_client_del_channel(client, conn, channel);
1079     } else {
1080       chu = silc_client_on_channel(channel, client_entry);
1081       if (chu) {
1082         silc_hash_table_del(client_entry->channels, channel);
1083         silc_hash_table_del(channel->user_list, client_entry);
1084         silc_free(chu);
1085       }
1086
1087       if (!silc_hash_table_count(client_entry->channels)) {
1088         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1089         res->context = client;
1090         res->sock = silc_socket_dup(conn->sock);
1091         res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1092         silc_schedule_task_add(client->schedule, conn->sock->sock,
1093                                silc_client_notify_check_client, res,
1094                                (5 + (silc_rng_get_rn16(client->rng) % 529)),
1095                                0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1096       }
1097     }
1098     break;
1099
1100   case SILC_NOTIFY_TYPE_KILLED:
1101     {
1102       /*
1103        * A client (maybe me) was killed from the network.
1104        */
1105       char *comment;
1106       SilcUInt32 comment_len;
1107
1108       SILC_LOG_DEBUG(("Notify: KILLED"));
1109
1110       /* Get Client ID */
1111       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1112       if (!tmp)
1113         goto out;
1114
1115       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1116       if (!client_id)
1117         goto out;
1118
1119       /* Find Client entry */
1120       client_entry = silc_client_get_client_by_id(client, conn, client_id);
1121       if (!client_entry)
1122         goto out;
1123
1124       /* Get comment */
1125       comment = silc_argument_get_arg_type(args, 2, &comment_len);
1126
1127       /* From protocol version 1.1 we get killer's client ID as well */
1128       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1129       if (tmp) {
1130         silc_free(client_id);
1131         client_id = NULL;
1132         id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1133         if (!id)
1134           goto out;
1135
1136         /* Find Client entry */
1137         if (id_type == SILC_ID_CLIENT) {
1138           /* Find Client entry */
1139           client_id = id;
1140           client_entry2 = silc_client_get_client_by_id(client, conn, 
1141                                                        client_id);
1142           if (!client_entry) {
1143             silc_client_notify_by_server_resolve(client, conn, packet, 
1144                                                  SILC_ID_CLIENT, client_id);
1145             goto out;
1146           }
1147         } else if (id_type == SILC_ID_SERVER) {
1148           /* Find Server entry */
1149           server_id = id;
1150           server = silc_client_get_server_by_id(client, conn, server_id);
1151           if (!server) {
1152             silc_client_notify_by_server_resolve(client, conn, packet, 
1153                                                  SILC_ID_SERVER, server_id);
1154             server = silc_client_add_server(client, conn, NULL, NULL,
1155                                             server_id);
1156             if (!server)
1157               goto out;
1158
1159             server->resolve_cmd_ident = conn->cmd_ident;
1160             server_id = NULL;
1161             goto out;
1162           }
1163
1164           if (server->resolve_cmd_ident) {
1165             SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1166             res->packet = silc_packet_context_dup(packet);
1167             res->context = client;
1168             res->sock = silc_socket_dup(conn->sock);
1169             silc_client_command_pending(conn, SILC_COMMAND_NONE, 
1170                                         server->resolve_cmd_ident,
1171                                         silc_client_notify_by_server_pending,
1172                                         res);
1173             goto out;
1174           }
1175       
1176           /* Save the pointer to the client_entry pointer */
1177           client_entry2 = (SilcClientEntry)server;
1178         } else {
1179           /* Find Channel entry */
1180           channel_id = id;
1181           channel = silc_client_get_channel_by_id(client, conn, channel_id);
1182           if (!channel) {
1183             silc_client_notify_by_server_resolve(client, conn, packet, 
1184                                                  SILC_ID_CHANNEL, channel_id);
1185             goto out;
1186           }
1187           
1188           /* Save the pointer to the client_entry pointer */
1189           client_entry2 = (SilcClientEntry)channel;
1190           silc_free(channel_id);
1191           channel_id = NULL;
1192         }
1193       }
1194
1195       /* Notify application. */
1196       client->internal->ops->notify(client, conn, type, client_entry, 
1197                                     comment, id_type, client_entry2);
1198
1199       if (client_entry != conn->local_entry)
1200         /* Remove the client from all channels and free it */
1201         silc_client_del_client(client, conn, client_entry);
1202     }
1203     break;
1204     
1205   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1206     {
1207       /*
1208        * A server quit the SILC network and some clients must be removed
1209        * from channels as they quit as well.
1210        */
1211       SilcClientEntry *clients = NULL;
1212       SilcUInt32 clients_count = 0;
1213       int i;
1214
1215       SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1216
1217       for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1218         /* Get Client ID */
1219         tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1220         if (tmp) {
1221           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1222           if (!client_id)
1223             goto out;
1224           
1225           /* Get the client entry */
1226           client_entry = silc_client_get_client_by_id(client, conn, client_id);
1227           if (client_entry) {
1228             clients = silc_realloc(clients, sizeof(*clients) * 
1229                                    (clients_count + 1));
1230             clients[clients_count] = client_entry;
1231             clients_count++;
1232           }
1233           silc_free(client_id);
1234         }
1235       }
1236       client_id = NULL;
1237
1238       /* Notify application. We don't keep server entries so the server
1239          entry is returned as NULL. The client's are returned as array
1240          of SilcClientEntry pointers. */
1241       client->internal->ops->notify(client, conn, type, NULL, 
1242                                     clients, clients_count);
1243
1244       for (i = 0; i < clients_count; i++) {
1245         /* Remove client from all channels */
1246         client_entry = clients[i];
1247         if (client_entry == conn->local_entry)
1248           continue;
1249
1250         /* Remove the client from all channels and free it */
1251         silc_client_del_client(client, conn, client_entry);
1252       }
1253       silc_free(clients);
1254
1255     }
1256     break;
1257
1258   case SILC_NOTIFY_TYPE_ERROR:
1259     {
1260       /*
1261        * Some has occurred and server is notifying us about it.
1262        */
1263       SilcStatus error;
1264
1265       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1266       if (!tmp && tmp_len != 1)
1267         goto out;
1268       error = (SilcStatus)tmp[0];
1269
1270       SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1271
1272       if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1273         tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1274         if (tmp) {
1275           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1276           if (!client_id)
1277             goto out;
1278           client_entry = silc_client_get_client_by_id(client, conn,
1279                                                       client_id);
1280           if (client_entry)
1281             silc_client_del_client(client, conn, client_entry);
1282         }
1283       }
1284
1285       /* Notify application. */
1286       client->internal->ops->notify(client, conn, type, error);
1287     }
1288     break;
1289
1290   case SILC_NOTIFY_TYPE_WATCH:
1291     {
1292       /*
1293        * Received notify about some client we are watching
1294        */
1295       SilcNotifyType notify = 0;
1296       bool del_client = FALSE;
1297
1298       SILC_LOG_DEBUG(("Notify: WATCH"));
1299
1300       /* Get sender Client ID */
1301       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1302       if (!tmp)
1303         goto out;
1304       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1305       if (!client_id)
1306         goto out;
1307
1308       /* Find Client entry and if not found query it */
1309       client_entry = silc_client_get_client_by_id(client, conn, client_id);
1310       if (!client_entry) {
1311         silc_client_notify_by_server_resolve(client, conn, packet, 
1312                                              SILC_ID_CLIENT, client_id);
1313         goto out;
1314       }
1315
1316       /* Get user mode */
1317       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1318       if (!tmp || tmp_len != 4)
1319         goto out;
1320       SILC_GET32_MSB(mode, tmp);
1321
1322       /* Get notify type */
1323       tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1324       if (tmp && tmp_len != 2)
1325         goto out;
1326       if (tmp)
1327         SILC_GET16_MSB(notify, tmp);
1328
1329       /* Get nickname */
1330       tmp = silc_argument_get_arg_type(args, 2, NULL);
1331       if (tmp) {
1332         char *tmp_nick = NULL;
1333
1334         if (client->internal->params->nickname_parse)
1335           client->internal->params->nickname_parse(client_entry->nickname,
1336                                                    &tmp_nick);
1337         else
1338           tmp_nick = strdup(tmp);
1339
1340         /* If same nick, the client was new to us and has become "present"
1341            to network.  Send NULL as nick to application. */
1342         if (tmp_nick && !strcmp(tmp, tmp_nick))
1343           tmp = NULL;
1344
1345         silc_free(tmp_nick);
1346       }
1347
1348       /* Notify application. */
1349       client->internal->ops->notify(client, conn, type, client_entry,
1350                                     tmp, mode, notify);
1351
1352       client_entry->mode = mode;
1353
1354       /* If nickname was changed, remove the client entry unless the
1355          client is on some channel */
1356       if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1357           !silc_hash_table_count(client_entry->channels))
1358         del_client = TRUE;
1359       else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1360                notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1361                notify == SILC_NOTIFY_TYPE_KILLED)
1362         del_client = TRUE;
1363
1364       if (del_client) {
1365         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1366         res->context = client;
1367         res->sock = silc_socket_dup(conn->sock);
1368         res->packet = client_id;
1369         client_id = NULL;
1370         silc_schedule_task_add(client->schedule, conn->sock->sock,
1371                                silc_client_notify_del_client_cb, res,
1372                                1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1373       }
1374     }
1375     break;
1376
1377   default:
1378     break;
1379   }
1380
1381  out:
1382   silc_notify_payload_free(payload);
1383   silc_free(client_id);
1384   silc_free(channel_id);
1385   silc_free(server_id);
1386 }