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