5221421390a3bdbe31fe489dbcb685744b0d2878
[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     silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
640                               client_entry->mode);
641
642     /* Remove the old from cache */
643     silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
644     
645     /* Replace old ID entry with new one on all channels. */
646     silc_client_replace_from_channels(client, conn, client_entry,
647                                       client_entry2);
648
649     /* Notify application */
650     client->internal->ops->notify(client, conn, type, 
651                                   client_entry, client_entry2);
652     
653     /* Free old client entry */
654     silc_client_del_client_entry(client, conn, client_entry);
655
656     break;
657
658   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
659     /*
660      * Someone changed a channel mode
661      */
662
663     SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
664
665     /* Get channel entry */
666     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
667                                 SILC_ID_CHANNEL);
668     if (!channel_id)
669       goto out;
670     channel = silc_client_get_channel_by_id(client, conn, channel_id);
671     if (!channel)
672       goto out;
673
674     /* Get ID */
675     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
676     if (!tmp)
677       goto out;
678     id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
679     if (!id)
680       goto out;
681
682     /* Find Client entry */
683     if (id_type == SILC_ID_CLIENT) {
684       /* Find Client entry */
685       client_id = id;
686       client_entry = silc_client_get_client_by_id(client, conn, client_id);
687       if (!client_entry) {
688         silc_client_channel_set_wait(client, conn, channel,
689                                      conn->cmd_ident + 1);
690         silc_client_notify_by_server_resolve(client, conn, packet, 
691                                              SILC_ID_CLIENT, client_id);
692         goto out;
693       }
694
695       if (!client_entry->nickname) {
696         if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
697           /* Attach to existing resolving */
698           SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
699           res->packet = silc_packet_context_dup(packet);
700           res->context = client;
701           res->sock = silc_socket_dup(conn->sock);
702           silc_client_command_pending(conn, SILC_COMMAND_NONE, 
703                                       client_entry->resolve_cmd_ident,
704                                       silc_client_notify_by_server_pending,
705                                       res);
706           goto out;
707         }
708
709         /* Do new resolving */
710         silc_client_channel_set_wait(client, conn, channel,
711                                      conn->cmd_ident + 1);
712         silc_client_notify_by_server_resolve(client, conn, packet, 
713                                              SILC_ID_CLIENT, client_id);
714         goto out;
715       }
716     } else if (id_type == SILC_ID_SERVER) {
717       /* Find Server entry */
718       server_id = id;
719       server = silc_client_get_server_by_id(client, conn, server_id);
720       if (!server) {
721         silc_client_channel_set_wait(client, conn, channel,
722                                      conn->cmd_ident + 1);
723         silc_client_notify_by_server_resolve(client, conn, packet, 
724                                              SILC_ID_SERVER, server_id);
725         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
726         if (!server)
727           goto out;
728
729         server->resolve_cmd_ident = conn->cmd_ident;
730         server_id = NULL;
731         goto out;
732       }
733
734       /* If entry being resoled, wait for it before processing this notify */
735       if (server->resolve_cmd_ident) {
736         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
737         res->packet = silc_packet_context_dup(packet);
738         res->context = client;
739         res->sock = silc_socket_dup(conn->sock);
740         silc_client_command_pending(conn, SILC_COMMAND_NONE, 
741                                     server->resolve_cmd_ident,
742                                     silc_client_notify_by_server_pending, res);
743         goto out;
744       }
745       
746       /* Save the pointer to the client_entry pointer */
747       client_entry = (SilcClientEntry)server;
748     } else {
749       /* Find Channel entry */
750       silc_free(channel_id);
751       channel_id = id;
752       client_entry = (SilcClientEntry)
753         silc_client_get_channel_by_id(client, conn, channel_id);
754       if (!client_entry) {
755         silc_client_channel_set_wait(client, conn, channel,
756                                      conn->cmd_ident + 1);
757         silc_client_notify_by_server_resolve(client, conn, packet, 
758                                              SILC_ID_CHANNEL, channel_id);
759         goto out;
760       }
761     }
762
763     /* Get the mode */
764     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
765     if (!tmp)
766       goto out;
767
768     SILC_GET32_MSB(mode, tmp);
769
770     /* If information is being resolved for this channel, wait for it */
771     if (channel->resolve_cmd_ident) {
772       silc_client_channel_wait(client, conn, channel, packet);
773       goto out;
774     }
775
776     /* Save the new mode */
777     channel->mode = mode;
778
779     /* Get the hmac */
780     tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
781     if (tmp) {
782       unsigned char hash[32];
783
784       if (channel->hmac)
785         silc_hmac_free(channel->hmac);
786       if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
787         goto out;
788
789       silc_hash_make(silc_hmac_get_hash(channel->hmac), 
790                      channel->key, channel->key_len / 8,
791                      hash);
792       silc_hmac_set_key(channel->hmac, hash, 
793                         silc_hash_len(silc_hmac_get_hash(channel->hmac)));
794       memset(hash, 0, sizeof(hash));
795     }
796
797     /* Notify application. The channel entry is sent last as this notify
798        is for channel but application don't know it from the arguments
799        sent by server. */
800     client->internal->ops->notify(client, conn, type, id_type,
801                                   client_entry, mode, NULL, tmp, channel);
802     break;
803
804   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
805     /*
806      * Someone changed user's mode on a channel
807      */
808
809     SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
810
811     /* Get channel entry */
812     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
813                                 SILC_ID_CHANNEL);
814     if (!channel_id)
815       goto out;
816     channel = silc_client_get_channel_by_id(client, conn, channel_id);
817     if (!channel)
818       break;
819
820     /* Get ID */
821     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
822     if (!tmp)
823       goto out;
824     id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
825     if (!id)
826       goto out;
827
828     /* Find Client entry */
829     if (id_type == SILC_ID_CLIENT) {
830       /* Find Client entry */
831       client_id = id;
832       client_entry = silc_client_get_client_by_id(client, conn, client_id);
833       if (!client_entry) {
834         silc_client_channel_set_wait(client, conn, channel,
835                                      conn->cmd_ident + 1);
836         silc_client_notify_by_server_resolve(client, conn, packet, 
837                                              SILC_ID_CLIENT, client_id);
838         goto out;
839       }
840
841       if (!client_entry->nickname) {
842         if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
843           /* Attach to existing resolving */
844           SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
845           res->packet = silc_packet_context_dup(packet);
846           res->context = client;
847           res->sock = silc_socket_dup(conn->sock);
848           silc_client_command_pending(conn, SILC_COMMAND_NONE, 
849                                       client_entry->resolve_cmd_ident,
850                                       silc_client_notify_by_server_pending,
851                                       res);
852           goto out;
853         }
854
855         /* Do new resolving */
856         silc_client_channel_set_wait(client, conn, channel,
857                                      conn->cmd_ident + 1);
858         silc_client_notify_by_server_resolve(client, conn, packet, 
859                                              SILC_ID_CLIENT, client_id);
860         goto out;
861       }
862     } else if (id_type == SILC_ID_SERVER) {
863       /* Find Server entry */
864       server_id = id;
865       server = silc_client_get_server_by_id(client, conn, server_id);
866       if (!server) {
867         silc_client_channel_set_wait(client, conn, channel,
868                                      conn->cmd_ident + 1);
869         silc_client_notify_by_server_resolve(client, conn, packet, 
870                                              SILC_ID_SERVER, server_id);
871         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
872         if (!server)
873           goto out;
874
875         server->resolve_cmd_ident = conn->cmd_ident;
876         server_id = NULL;
877         goto out;
878       }
879
880       /* If entry being resoled, wait for it before processing this notify */
881       if (server->resolve_cmd_ident) {
882         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
883         res->packet = silc_packet_context_dup(packet);
884         res->context = client;
885         res->sock = silc_socket_dup(conn->sock);
886         silc_client_command_pending(conn, SILC_COMMAND_NONE, 
887                                     server->resolve_cmd_ident,
888                                     silc_client_notify_by_server_pending, res);
889         goto out;
890       }
891
892       /* Save the pointer to the client_entry pointer */
893       client_entry = (SilcClientEntry)server;
894     } else {
895       /* Find Channel entry */
896       silc_free(channel_id);
897       channel_id = id;
898       client_entry = (SilcClientEntry)
899         silc_client_get_channel_by_id(client, conn, channel_id);
900       if (!client_entry) {
901         silc_client_channel_set_wait(client, conn, channel,
902                                      conn->cmd_ident + 1);
903         silc_client_notify_by_server_resolve(client, conn, packet, 
904                                              SILC_ID_CHANNEL, channel_id);
905         goto out;
906       }
907     }
908
909     /* Get the mode */
910     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
911     if (!tmp)
912       goto out;
913
914     SILC_GET32_MSB(mode, tmp);
915
916     /* If information is being resolved for this channel, wait for it */
917     if (channel->resolve_cmd_ident) {
918       silc_client_channel_wait(client, conn, channel, packet);
919       goto out;
920     }
921
922     /* Get target Client ID */
923     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
924     if (!tmp)
925       goto out;
926
927     silc_free(client_id);
928     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
929     if (!client_id)
930       goto out;
931
932     /* Find target Client entry */
933     client_entry2 = 
934       silc_client_get_client_by_id(client, conn, client_id);
935     if (!client_entry2) {
936       silc_client_notify_by_server_resolve(client, conn, packet, 
937                                            SILC_ID_CLIENT, client_id);
938       goto out;
939     }
940
941     /* Save the mode */
942     chu = silc_client_on_channel(channel, client_entry2);
943     if (chu)
944       chu->mode = mode;
945
946     /* Notify application. The channel entry is sent last as this notify
947        is for channel but application don't know it from the arguments
948        sent by server. */
949     client->internal->ops->notify(client, conn, type,
950                                   id_type, client_entry, mode, 
951                                   client_entry2, channel);
952     break;
953
954   case SILC_NOTIFY_TYPE_MOTD:
955     /*
956      * Received Message of the day
957      */
958
959     SILC_LOG_DEBUG(("Notify: MOTD"));
960
961     /* Get motd */
962     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
963     if (!tmp)
964       goto out;
965     
966     /* Notify application */
967     client->internal->ops->notify(client, conn, type, tmp);
968     break;
969
970   case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
971     /*
972      * Router has enforced a new ID to a channel. Let's change the old
973      * ID to the one provided here.
974      */
975
976     SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
977
978     /* Get the old ID */
979     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
980     if (!tmp)
981       goto out;
982     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
983     if (!channel_id)
984       goto out;
985
986     /* Get the channel entry */
987     channel = silc_client_get_channel_by_id(client, conn, channel_id);
988     if (!channel)
989       goto out;
990
991     silc_free(channel_id);
992     channel_id = NULL;
993
994     /* Get the new ID */
995     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
996     if (!tmp)
997       goto out;
998     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
999     if (!channel_id)
1000       goto out;
1001
1002     /* Replace the Channel ID */
1003     if (silc_client_replace_channel_id(client, conn, channel, channel_id))
1004       channel_id = NULL;
1005
1006     /* Notify application */
1007     client->internal->ops->notify(client, conn, type, channel, channel);
1008     break;
1009
1010   case SILC_NOTIFY_TYPE_KICKED:
1011     /*
1012      * A client (maybe me) was kicked from a channel
1013      */
1014
1015     SILC_LOG_DEBUG(("Notify: KICKED"));
1016
1017     /* Get Client ID */
1018     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1019     if (!tmp)
1020       goto out;
1021
1022     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1023     if (!client_id)
1024       goto out;
1025
1026     /* Find Client entry */
1027     client_entry = silc_client_get_client_by_id(client, conn, client_id);
1028     if (!client_entry)
1029       goto out;
1030
1031     /* Get channel entry */
1032     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1033                                 SILC_ID_CHANNEL);
1034     if (!channel_id)
1035       goto out;
1036     channel = silc_client_get_channel_by_id(client, conn, channel_id);
1037     if (!channel)
1038       break;
1039
1040     /* From protocol version 1.1 we get the kicker's client ID as well */
1041     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1042     if (tmp) {
1043       silc_free(client_id);
1044       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1045       if (!client_id)
1046         goto out;
1047
1048       /* Find kicker's client entry and if not found resolve it */
1049       client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
1050       if (!client_entry2) {
1051         silc_client_notify_by_server_resolve(client, conn, packet, 
1052                                              SILC_ID_CLIENT, client_id);
1053         goto out;
1054       } else {
1055         if (client_entry2 != conn->local_entry)
1056           silc_client_nickname_format(client, conn, client_entry2);
1057       }
1058     }
1059
1060     /* Get comment */
1061     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1062
1063     /* Notify application. The channel entry is sent last as this notify
1064        is for channel but application don't know it from the arguments
1065        sent by server. */
1066     client->internal->ops->notify(client, conn, type, client_entry, tmp, 
1067                                   client_entry2, channel);
1068
1069     /* Remove kicked client from channel */
1070     if (client_entry == conn->local_entry) {
1071       /* If I was kicked from channel, remove the channel */
1072       if (conn->current_channel == channel)
1073         conn->current_channel = NULL;
1074       silc_client_del_channel(client, conn, channel);
1075     } else {
1076       chu = silc_client_on_channel(channel, client_entry);
1077       if (chu) {
1078         silc_hash_table_del(client_entry->channels, channel);
1079         silc_hash_table_del(channel->user_list, client_entry);
1080         silc_free(chu);
1081       }
1082
1083       if (!silc_hash_table_count(client_entry->channels)) {
1084         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1085         res->context = client;
1086         res->sock = silc_socket_dup(conn->sock);
1087         res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1088         silc_schedule_task_add(client->schedule, conn->sock->sock,
1089                                silc_client_notify_check_client, res,
1090                                (5 + (silc_rng_get_rn16(client->rng) % 529)),
1091                                0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1092       }
1093     }
1094     break;
1095
1096   case SILC_NOTIFY_TYPE_KILLED:
1097     {
1098       /*
1099        * A client (maybe me) was killed from the network.
1100        */
1101       char *comment;
1102       SilcUInt32 comment_len;
1103
1104       SILC_LOG_DEBUG(("Notify: KILLED"));
1105
1106       /* Get Client ID */
1107       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1108       if (!tmp)
1109         goto out;
1110
1111       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1112       if (!client_id)
1113         goto out;
1114
1115       /* Find Client entry */
1116       client_entry = silc_client_get_client_by_id(client, conn, client_id);
1117       if (!client_entry)
1118         goto out;
1119
1120       /* Get comment */
1121       comment = silc_argument_get_arg_type(args, 2, &comment_len);
1122
1123       /* From protocol version 1.1 we get killer's client ID as well */
1124       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1125       if (tmp) {
1126         silc_free(client_id);
1127         client_id = NULL;
1128         id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1129         if (!id)
1130           goto out;
1131
1132         /* Find Client entry */
1133         if (id_type == SILC_ID_CLIENT) {
1134           /* Find Client entry */
1135           client_id = id;
1136           client_entry2 = silc_client_get_client_by_id(client, conn, 
1137                                                        client_id);
1138           if (!client_entry) {
1139             silc_client_notify_by_server_resolve(client, conn, packet, 
1140                                                  SILC_ID_CLIENT, client_id);
1141             goto out;
1142           }
1143         } else if (id_type == SILC_ID_SERVER) {
1144           /* Find Server entry */
1145           server_id = id;
1146           server = silc_client_get_server_by_id(client, conn, server_id);
1147           if (!server) {
1148             silc_client_notify_by_server_resolve(client, conn, packet, 
1149                                                  SILC_ID_SERVER, server_id);
1150             server = silc_client_add_server(client, conn, NULL, NULL,
1151                                             server_id);
1152             if (!server)
1153               goto out;
1154
1155             server->resolve_cmd_ident = conn->cmd_ident;
1156             server_id = NULL;
1157             goto out;
1158           }
1159
1160           if (server->resolve_cmd_ident) {
1161             SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1162             res->packet = silc_packet_context_dup(packet);
1163             res->context = client;
1164             res->sock = silc_socket_dup(conn->sock);
1165             silc_client_command_pending(conn, SILC_COMMAND_NONE, 
1166                                         server->resolve_cmd_ident,
1167                                         silc_client_notify_by_server_pending,
1168                                         res);
1169             goto out;
1170           }
1171       
1172           /* Save the pointer to the client_entry pointer */
1173           client_entry2 = (SilcClientEntry)server;
1174         } else {
1175           /* Find Channel entry */
1176           channel_id = id;
1177           channel = silc_client_get_channel_by_id(client, conn, channel_id);
1178           if (!channel) {
1179             silc_client_notify_by_server_resolve(client, conn, packet, 
1180                                                  SILC_ID_CHANNEL, channel_id);
1181             goto out;
1182           }
1183           
1184           /* Save the pointer to the client_entry pointer */
1185           client_entry2 = (SilcClientEntry)channel;
1186           silc_free(channel_id);
1187           channel_id = NULL;
1188         }
1189       }
1190
1191       /* Notify application. */
1192       client->internal->ops->notify(client, conn, type, client_entry, 
1193                                     comment, id_type, client_entry2);
1194
1195       if (client_entry != conn->local_entry)
1196         /* Remove the client from all channels and free it */
1197         silc_client_del_client(client, conn, client_entry);
1198     }
1199     break;
1200     
1201   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1202     {
1203       /*
1204        * A server quit the SILC network and some clients must be removed
1205        * from channels as they quit as well.
1206        */
1207       SilcClientEntry *clients = NULL;
1208       SilcUInt32 clients_count = 0;
1209       int i;
1210
1211       SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1212
1213       for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1214         /* Get Client ID */
1215         tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1216         if (tmp) {
1217           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1218           if (!client_id)
1219             goto out;
1220           
1221           /* Get the client entry */
1222           client_entry = silc_client_get_client_by_id(client, conn, client_id);
1223           if (client_entry) {
1224             clients = silc_realloc(clients, sizeof(*clients) * 
1225                                    (clients_count + 1));
1226             clients[clients_count] = client_entry;
1227             clients_count++;
1228           }
1229           silc_free(client_id);
1230         }
1231       }
1232       client_id = NULL;
1233
1234       /* Notify application. We don't keep server entries so the server
1235          entry is returned as NULL. The client's are returned as array
1236          of SilcClientEntry pointers. */
1237       client->internal->ops->notify(client, conn, type, NULL, 
1238                                     clients, clients_count);
1239
1240       for (i = 0; i < clients_count; i++) {
1241         /* Remove client from all channels */
1242         client_entry = clients[i];
1243         if (client_entry == conn->local_entry)
1244           continue;
1245
1246         /* Remove the client from all channels and free it */
1247         silc_client_del_client(client, conn, client_entry);
1248       }
1249       silc_free(clients);
1250
1251     }
1252     break;
1253
1254   case SILC_NOTIFY_TYPE_ERROR:
1255     {
1256       /*
1257        * Some has occurred and server is notifying us about it.
1258        */
1259       SilcStatus error;
1260
1261       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1262       if (!tmp && tmp_len != 1)
1263         goto out;
1264       error = (SilcStatus)tmp[0];
1265
1266       SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1267
1268       if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1269         tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1270         if (tmp) {
1271           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1272           if (!client_id)
1273             goto out;
1274           client_entry = silc_client_get_client_by_id(client, conn,
1275                                                       client_id);
1276           if (client_entry)
1277             silc_client_del_client(client, conn, client_entry);
1278         }
1279       }
1280
1281       /* Notify application. */
1282       client->internal->ops->notify(client, conn, type, error);
1283     }
1284     break;
1285
1286   case SILC_NOTIFY_TYPE_WATCH:
1287     {
1288       /*
1289        * Received notify about some client we are watching
1290        */
1291       SilcNotifyType notify = 0;
1292       bool del_client = FALSE;
1293
1294       SILC_LOG_DEBUG(("Notify: WATCH"));
1295
1296       /* Get sender Client ID */
1297       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1298       if (!tmp)
1299         goto out;
1300       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1301       if (!client_id)
1302         goto out;
1303
1304       /* Find Client entry and if not found query it */
1305       client_entry = silc_client_get_client_by_id(client, conn, client_id);
1306       if (!client_entry) {
1307         silc_client_notify_by_server_resolve(client, conn, packet, 
1308                                              SILC_ID_CLIENT, client_id);
1309         goto out;
1310       }
1311
1312       /* Get user mode */
1313       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1314       if (!tmp || tmp_len != 4)
1315         goto out;
1316       SILC_GET32_MSB(mode, tmp);
1317
1318       /* Get notify type */
1319       tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1320       if (tmp && tmp_len != 2)
1321         goto out;
1322       if (tmp)
1323         SILC_GET16_MSB(notify, tmp);
1324
1325       /* Get nickname */
1326       tmp = silc_argument_get_arg_type(args, 2, NULL);
1327       if (tmp) {
1328         char *tmp_nick = NULL;
1329
1330         if (client->internal->params->nickname_parse)
1331           client->internal->params->nickname_parse(client_entry->nickname,
1332                                                    &tmp_nick);
1333         else
1334           tmp_nick = strdup(tmp);
1335
1336         /* If same nick, the client was new to us and has become "present"
1337            to network.  Send NULL as nick to application. */
1338         if (tmp_nick && !strcmp(tmp, tmp_nick))
1339           tmp = NULL;
1340
1341         silc_free(tmp_nick);
1342       }
1343
1344       /* Notify application. */
1345       client->internal->ops->notify(client, conn, type, client_entry,
1346                                     tmp, mode, notify);
1347
1348       client_entry->mode = mode;
1349
1350       /* If nickname was changed, remove the client entry unless the
1351          client is on some channel */
1352       if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1353           !silc_hash_table_count(client_entry->channels))
1354         del_client = TRUE;
1355       else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1356                notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1357                notify == SILC_NOTIFY_TYPE_KILLED)
1358         del_client = TRUE;
1359
1360       if (del_client) {
1361         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1362         res->context = client;
1363         res->sock = silc_socket_dup(conn->sock);
1364         res->packet = client_id;
1365         client_id = NULL;
1366         silc_schedule_task_add(client->schedule, conn->sock->sock,
1367                                silc_client_notify_del_client_cb, res,
1368                                1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1369       }
1370     }
1371     break;
1372
1373   default:
1374     break;
1375   }
1376
1377  out:
1378   silc_notify_payload_free(payload);
1379   silc_free(client_id);
1380   silc_free(channel_id);
1381   silc_free(server_id);
1382 }