Merged silc_1_0_branch to trunk.
[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 - 2003 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 Channel ID */
283     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
284     if (!tmp)
285       goto out;
286
287     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
288     if (!channel_id)
289       goto out;
290
291     /* Get channel entry */
292     channel = silc_client_get_channel_by_id(client, conn, channel_id);
293     if (!channel)
294       break;
295
296     /* Get Client ID */
297     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
298     if (!tmp)
299       goto out;
300
301     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
302     if (!client_id)
303       goto out;
304
305     /* Find Client entry and if not found query it */
306     client_entry = silc_client_get_client_by_id(client, conn, client_id);
307     if (!client_entry) {
308       silc_client_channel_set_wait(client, conn, channel,
309                                    conn->cmd_ident + 1);
310       silc_client_notify_by_server_resolve(client, conn, packet,
311                                            SILC_ID_CLIENT, client_id);
312       goto out;
313     }
314
315     /* If nickname or username hasn't been resolved, do so */
316     if (!client_entry->nickname || !client_entry->username) {
317       if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
318         /* Attach to existing resolving */
319         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
320         res->packet = silc_packet_context_dup(packet);
321         res->context = client;
322         res->sock = silc_socket_dup(conn->sock);
323         silc_client_command_pending(conn, SILC_COMMAND_NONE,
324                                     client_entry->resolve_cmd_ident,
325                                     silc_client_notify_by_server_pending,
326                                     res);
327         goto out;
328       }
329
330       /* Do new resolving */
331       silc_client_channel_set_wait(client, conn, channel,
332                                    conn->cmd_ident + 1);
333       silc_client_notify_by_server_resolve(client, conn, packet,
334                                            SILC_ID_CLIENT, client_id);
335       client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
336       client_entry->resolve_cmd_ident = conn->cmd_ident;
337       goto out;
338     } else {
339       if (client_entry != conn->local_entry)
340         silc_client_nickname_format(client, conn, client_entry);
341     }
342
343     /* If information is being resolved for this channel, wait for it */
344     if (channel->resolve_cmd_ident) {
345       silc_client_channel_wait(client, conn, channel, packet);
346       goto out;
347     }
348
349     /* Join the client to channel */
350     if (!silc_client_on_channel(channel, client_entry)) {
351       chu = silc_calloc(1, sizeof(*chu));
352       chu->client = client_entry;
353       chu->channel = channel;
354       silc_hash_table_add(channel->user_list, client_entry, chu);
355       silc_hash_table_add(client_entry->channels, channel, chu);
356     }
357
358     /* Notify application. The channel entry is sent last as this notify
359        is for channel but application don't know it from the arguments
360        sent by server. */
361     client->internal->ops->notify(client, conn, type, client_entry, channel);
362     break;
363
364   case SILC_NOTIFY_TYPE_LEAVE:
365     /*
366      * Someone has left a channel. We will remove it from the channel but
367      * we'll keep it in the cache in case we'll need it later.
368      */
369
370     SILC_LOG_DEBUG(("Notify: LEAVE"));
371
372     /* Get Client ID */
373     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
374     if (!tmp)
375       goto out;
376
377     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
378     if (!client_id)
379       goto out;
380
381     /* Find Client entry */
382     client_entry =
383       silc_client_get_client_by_id(client, conn, client_id);
384     if (!client_entry)
385       goto out;
386
387     /* Get channel entry */
388     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
389                                 SILC_ID_CHANNEL);
390     if (!channel_id)
391       goto out;
392     channel = silc_client_get_channel_by_id(client, conn, channel_id);
393     if (!channel)
394       break;
395
396     /* Remove client from channel */
397     chu = silc_client_on_channel(channel, client_entry);
398     if (chu) {
399       silc_hash_table_del(client_entry->channels, channel);
400       silc_hash_table_del(channel->user_list, client_entry);
401       silc_free(chu);
402     }
403
404     /* Some client implementations actually quit network by first doing
405        LEAVE and then immediately SIGNOFF.  We'll check for this by doing
406        check for the client after 5 - 34 seconds.  If it is not valid after
407        that we'll remove the client from cache. */
408     if (!silc_hash_table_count(client_entry->channels)) {
409       SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
410       res->context = client;
411       res->sock = silc_socket_dup(conn->sock);
412       res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
413       silc_schedule_task_add(client->schedule, conn->sock->sock,
414                              silc_client_notify_check_client, res,
415                              (5 + (silc_rng_get_rn16(client->rng) % 29)),
416                              0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
417     }
418
419     /* Notify application. The channel entry is sent last as this notify
420        is for channel but application don't know it from the arguments
421        sent by server. */
422     client->internal->ops->notify(client, conn, type, client_entry, channel);
423     break;
424
425   case SILC_NOTIFY_TYPE_SIGNOFF:
426     /*
427      * Someone left SILC. We'll remove it from all channels and from cache.
428      */
429
430     SILC_LOG_DEBUG(("Notify: SIGNOFF"));
431
432     /* Get Client ID */
433     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
434     if (!tmp)
435       goto out;
436
437     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
438     if (!client_id)
439       goto out;
440
441     /* Find Client entry */
442     client_entry =
443       silc_client_get_client_by_id(client, conn, client_id);
444     if (!client_entry)
445       goto out;
446
447     /* Remove from all channels */
448     silc_client_remove_from_channels(client, conn, client_entry);
449
450     /* Remove from cache */
451     silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
452
453     /* Get signoff message */
454     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
455     if (tmp_len > 128)
456       tmp = NULL;
457
458     /* Notify application */
459     client->internal->ops->notify(client, conn, type, client_entry, tmp);
460
461     /* Free data */
462     silc_client_del_client_entry(client, conn, client_entry);
463     break;
464
465   case SILC_NOTIFY_TYPE_TOPIC_SET:
466     /*
467      * Someone set the topic on a channel.
468      */
469
470     SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
471
472     /* Get channel entry */
473     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
474                                 SILC_ID_CHANNEL);
475     if (!channel_id)
476       goto out;
477     channel = silc_client_get_channel_by_id(client, conn, channel_id);
478     if (!channel)
479       break;
480
481     /* Get ID */
482     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
483     if (!tmp)
484       goto out;
485     id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
486     if (!id)
487       goto out;
488
489     /* Find Client entry */
490     if (id_type == SILC_ID_CLIENT) {
491       /* Find Client entry */
492       client_id = id;
493       client_entry = silc_client_get_client_by_id(client, conn, client_id);
494       if (!client_entry) {
495         silc_client_channel_set_wait(client, conn, channel,
496                                      conn->cmd_ident + 1);
497         silc_client_notify_by_server_resolve(client, conn, packet,
498                                              SILC_ID_CLIENT, client_id);
499         goto out;
500       }
501     } else if (id_type == SILC_ID_SERVER) {
502       /* Find Server entry */
503       server_id = id;
504       server = silc_client_get_server_by_id(client, conn, server_id);
505       if (!server) {
506         silc_client_channel_set_wait(client, conn, channel,
507                                      conn->cmd_ident + 1);
508         silc_client_notify_by_server_resolve(client, conn, packet,
509                                              SILC_ID_SERVER, server_id);
510         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
511         if (!server)
512           goto out;
513
514         server->resolve_cmd_ident = conn->cmd_ident;
515         server_id = NULL;
516         goto out;
517       }
518
519       /* If entry being resoled, wait for it before processing this notify */
520       if (server->resolve_cmd_ident) {
521         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
522         res->packet = silc_packet_context_dup(packet);
523         res->context = client;
524         res->sock = silc_socket_dup(conn->sock);
525         silc_client_command_pending(conn, SILC_COMMAND_NONE,
526                                     server->resolve_cmd_ident,
527                                     silc_client_notify_by_server_pending, res);
528         goto out;
529       }
530
531       /* Save the pointer to the client_entry pointer */
532       client_entry = (SilcClientEntry)server;
533     } else {
534       /* Find Channel entry */
535       silc_free(channel_id);
536       channel_id = id;
537       client_entry = (SilcClientEntry)
538         silc_client_get_channel_by_id(client, conn, channel_id);
539       if (!client_entry) {
540         silc_client_channel_set_wait(client, conn, channel,
541                                      conn->cmd_ident + 1);
542         silc_client_notify_by_server_resolve(client, conn, packet,
543                                              SILC_ID_CHANNEL, channel_id);
544         goto out;
545       }
546     }
547
548     /* Get topic */
549     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
550     if (!tmp)
551       goto out;
552
553     /* If information is being resolved for this channel, wait for it */
554     if (channel->resolve_cmd_ident) {
555       silc_client_channel_wait(client, conn, channel, packet);
556       goto out;
557     }
558
559     /* Notify application. The channel entry is sent last as this notify
560        is for channel but application don't know it from the arguments
561        sent by server. */
562     client->internal->ops->notify(client, conn, type, id_type,
563                                   client_entry, tmp, channel);
564
565     break;
566
567   case SILC_NOTIFY_TYPE_NICK_CHANGE:
568     /*
569      * Someone changed their nickname. If we don't have entry for the new
570      * ID we will query it and return here after it's done. After we've
571      * returned we fetch the old entry and free it and notify the
572      * application.
573      */
574
575     SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
576
577     /* Get old Client ID */
578     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
579     if (!tmp)
580       goto out;
581
582     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
583     if (!client_id)
584       goto out;
585
586     /* Ignore my ID */
587     if (conn->local_id && SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
588       break;
589
590     /* Find old Client entry */
591     client_entry = silc_client_get_client_by_id(client, conn, client_id);
592     if (!client_entry)
593       goto out;
594     silc_free(client_id);
595     client_id = NULL;
596
597     /* Wait for resolving if necessary */
598     if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
599       SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
600       res->packet = silc_packet_context_dup(packet);
601       res->context = client;
602       res->sock = silc_socket_dup(conn->sock);
603       silc_client_command_pending(conn, SILC_COMMAND_NONE,
604                                   client_entry->resolve_cmd_ident,
605                                   silc_client_notify_by_server_pending, res);
606       goto out;
607     }
608
609     client_entry->valid = FALSE;
610
611     /* Get new Client ID */
612     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
613     if (!tmp)
614       goto out;
615
616     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
617     if (!client_id)
618       goto out;
619
620     /* Take the nickname */
621     tmp = silc_argument_get_arg_type(args, 3, NULL);
622     if (!tmp)
623       goto out;
624
625     /* Check whether nickname changed at all.  It is possible that nick
626        change notify is received but nickname didn't change, only the
627        ID changes.  Check whether the hashes in the Client ID match, if
628        they do nickname didn't change. */
629     if (SILC_ID_COMPARE_HASH(client_entry->id, client_id) &&
630         !strcmp(tmp, client_entry->nickname)) {
631       /* Nickname didn't change.  Update only Client ID. */
632       silc_idcache_del_by_context(conn->internal->client_cache,
633                                   client_entry);
634       silc_free(client_entry->id);
635       client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
636       silc_idcache_add(conn->internal->client_cache, strdup(tmp),
637                        client_entry->id, client_entry, 0, NULL);
638
639       /* Notify application */
640       client->internal->ops->notify(client, conn, type,
641                                     client_entry, client_entry);
642       break;
643     }
644
645     /* Create new client entry, and save all old information with the
646        new nickname and client ID */
647     client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
648                                            client_entry->realname,
649                                            silc_id_dup(client_id,
650                                                        SILC_ID_CLIENT), 0);
651     if (!client_entry2)
652       goto out;
653
654     if (client_entry->server)
655       client_entry2->server = strdup(client_entry->server);
656     if (client_entry->username)
657       client_entry2->username = strdup(client_entry->username);
658     if (client_entry->hostname)
659       client_entry2->hostname = strdup(client_entry->hostname);
660     client_entry2->fingerprint = client_entry->fingerprint;
661     client_entry2->fingerprint_len = client_entry->fingerprint_len;
662     client_entry->fingerprint = NULL;
663     client_entry->fingerprint_len = 0;
664     silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
665                               client_entry->mode);
666
667     /* Remove the old from cache */
668     silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
669
670     /* Replace old ID entry with new one on all channels. */
671     silc_client_replace_from_channels(client, conn, client_entry,
672                                       client_entry2);
673
674     /* Notify application */
675     client->internal->ops->notify(client, conn, type,
676                                   client_entry, client_entry2);
677
678     /* Free old client entry */
679     silc_client_del_client_entry(client, conn, client_entry);
680
681     break;
682
683   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
684     {
685       /*
686        * Someone changed a channel mode
687        */
688       char *passphrase, *cipher, *hmac;
689       SilcPublicKey founder_key = NULL;
690       SilcBufferStruct chpks;
691
692       SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
693
694       /* Get channel entry */
695       channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
696                                   SILC_ID_CHANNEL);
697       if (!channel_id)
698         goto out;
699       channel = silc_client_get_channel_by_id(client, conn, channel_id);
700       if (!channel)
701         goto out;
702
703       /* Get ID */
704       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
705       if (!tmp)
706         goto out;
707       id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
708       if (!id)
709         goto out;
710
711       /* Find Client entry */
712       if (id_type == SILC_ID_CLIENT) {
713         /* Find Client entry */
714         client_id = id;
715         client_entry = silc_client_get_client_by_id(client, conn, client_id);
716         if (!client_entry) {
717           silc_client_channel_set_wait(client, conn, channel,
718                                        conn->cmd_ident + 1);
719           silc_client_notify_by_server_resolve(client, conn, packet,
720                                                SILC_ID_CLIENT, client_id);
721           goto out;
722         }
723
724         if (!client_entry->nickname) {
725           if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
726             /* Attach to existing resolving */
727             SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
728             res->packet = silc_packet_context_dup(packet);
729             res->context = client;
730             res->sock = silc_socket_dup(conn->sock);
731             silc_client_command_pending(conn, SILC_COMMAND_NONE,
732                                         client_entry->resolve_cmd_ident,
733                                         silc_client_notify_by_server_pending,
734                                         res);
735             goto out;
736           }
737
738           /* Do new resolving */
739           silc_client_channel_set_wait(client, conn, channel,
740                                        conn->cmd_ident + 1);
741           silc_client_notify_by_server_resolve(client, conn, packet,
742                                                SILC_ID_CLIENT, client_id);
743           client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
744           client_entry->resolve_cmd_ident = conn->cmd_ident;
745           goto out;
746         }
747       } else if (id_type == SILC_ID_SERVER) {
748         /* Find Server entry */
749         server_id = id;
750         server = silc_client_get_server_by_id(client, conn, server_id);
751         if (!server) {
752           silc_client_channel_set_wait(client, conn, channel,
753                                        conn->cmd_ident + 1);
754           silc_client_notify_by_server_resolve(client, conn, packet,
755                                                SILC_ID_SERVER, server_id);
756           server = silc_client_add_server(client, conn, NULL, NULL, server_id);
757           if (!server)
758             goto out;
759
760           server->resolve_cmd_ident = conn->cmd_ident;
761           server_id = NULL;
762           goto out;
763         }
764
765         /* If entry being resoled, wait for it before processing this notify */
766         if (server->resolve_cmd_ident) {
767           SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
768           res->packet = silc_packet_context_dup(packet);
769           res->context = client;
770           res->sock = silc_socket_dup(conn->sock);
771           silc_client_command_pending(conn, SILC_COMMAND_NONE,
772                                       server->resolve_cmd_ident,
773                                       silc_client_notify_by_server_pending,
774                                       res);
775           goto out;
776         }
777
778         /* Save the pointer to the client_entry pointer */
779         client_entry = (SilcClientEntry)server;
780       } else {
781         /* Find Channel entry */
782         silc_free(channel_id);
783         channel_id = id;
784         client_entry = (SilcClientEntry)
785           silc_client_get_channel_by_id(client, conn, channel_id);
786         if (!client_entry) {
787           silc_client_channel_set_wait(client, conn, channel,
788                                        conn->cmd_ident + 1);
789           silc_client_notify_by_server_resolve(client, conn, packet,
790                                                SILC_ID_CHANNEL, channel_id);
791           goto out;
792         }
793       }
794
795       /* Get the mode */
796       tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
797       if (!tmp)
798         goto out;
799
800       SILC_GET32_MSB(mode, tmp);
801
802       /* If information is being resolved for this channel, wait for it */
803       if (channel->resolve_cmd_ident) {
804         silc_client_channel_wait(client, conn, channel, packet);
805         goto out;
806       }
807
808       /* Save the new mode */
809       channel->mode = mode;
810
811       /* Get the cipher */
812       cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
813
814       /* Get the hmac */
815       hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
816       if (hmac) {
817         unsigned char hash[32];
818
819         if (channel->hmac)
820           silc_hmac_free(channel->hmac);
821         if (!silc_hmac_alloc(hmac, NULL, &channel->hmac))
822           goto out;
823
824         silc_hash_make(silc_hmac_get_hash(channel->hmac),
825                        channel->key, channel->key_len / 8,
826                        hash);
827         silc_hmac_set_key(channel->hmac, hash,
828                           silc_hash_len(silc_hmac_get_hash(channel->hmac)));
829         memset(hash, 0, sizeof(hash));
830       }
831
832       /* Get the passphrase if it was set */
833       passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
834
835       /* Get the channel founder key if it was set */
836       tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
837       if (tmp) {
838         if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len, &founder_key))
839           founder_key = NULL;
840       }
841
842       /* Get the channel public key that was added or removed */
843       tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
844       if (tmp)
845         silc_buffer_set(&chpks, tmp, tmp_len);
846
847       /* Notify application. The channel entry is sent last as this notify
848          is for channel but application don't know it from the arguments
849          sent by server. */
850       client->internal->ops->notify(client, conn, type, id_type,
851                                     client_entry, mode, cipher, hmac,
852                                     passphrase, founder_key,
853                                     tmp ? &chpks : NULL, channel);
854
855       if (founder_key)
856         silc_pkcs_public_key_free(founder_key);
857     }
858     break;
859
860   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
861     /*
862      * Someone changed user's mode on a channel
863      */
864
865     SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
866
867     /* Get channel entry */
868     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
869                                 SILC_ID_CHANNEL);
870     if (!channel_id)
871       goto out;
872     channel = silc_client_get_channel_by_id(client, conn, channel_id);
873     if (!channel)
874       break;
875
876     /* Get ID */
877     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
878     if (!tmp)
879       goto out;
880     id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
881     if (!id)
882       goto out;
883
884     /* Find Client entry */
885     if (id_type == SILC_ID_CLIENT) {
886       /* Find Client entry */
887       client_id = id;
888       client_entry = silc_client_get_client_by_id(client, conn, client_id);
889       if (!client_entry) {
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
897       if (!client_entry->nickname) {
898         if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
899           /* Attach to existing resolving */
900           SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
901           res->packet = silc_packet_context_dup(packet);
902           res->context = client;
903           res->sock = silc_socket_dup(conn->sock);
904           silc_client_command_pending(conn, SILC_COMMAND_NONE,
905                                       client_entry->resolve_cmd_ident,
906                                       silc_client_notify_by_server_pending,
907                                       res);
908           goto out;
909         }
910
911         /* Do new resolving */
912         silc_client_channel_set_wait(client, conn, channel,
913                                      conn->cmd_ident + 1);
914         silc_client_notify_by_server_resolve(client, conn, packet,
915                                              SILC_ID_CLIENT, client_id);
916         client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
917         client_entry->resolve_cmd_ident = conn->cmd_ident;
918         goto out;
919       }
920     } else if (id_type == SILC_ID_SERVER) {
921       /* Find Server entry */
922       server_id = id;
923       server = silc_client_get_server_by_id(client, conn, server_id);
924       if (!server) {
925         silc_client_channel_set_wait(client, conn, channel,
926                                      conn->cmd_ident + 1);
927         silc_client_notify_by_server_resolve(client, conn, packet,
928                                              SILC_ID_SERVER, server_id);
929         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
930         if (!server)
931           goto out;
932
933         server->resolve_cmd_ident = conn->cmd_ident;
934         server_id = NULL;
935         goto out;
936       }
937
938       /* If entry being resoled, wait for it before processing this notify */
939       if (server->resolve_cmd_ident) {
940         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
941         res->packet = silc_packet_context_dup(packet);
942         res->context = client;
943         res->sock = silc_socket_dup(conn->sock);
944         silc_client_command_pending(conn, SILC_COMMAND_NONE,
945                                     server->resolve_cmd_ident,
946                                     silc_client_notify_by_server_pending, res);
947         goto out;
948       }
949
950       /* Save the pointer to the client_entry pointer */
951       client_entry = (SilcClientEntry)server;
952     } else {
953       /* Find Channel entry */
954       silc_free(channel_id);
955       channel_id = id;
956       client_entry = (SilcClientEntry)
957         silc_client_get_channel_by_id(client, conn, channel_id);
958       if (!client_entry) {
959         silc_client_channel_set_wait(client, conn, channel,
960                                      conn->cmd_ident + 1);
961         silc_client_notify_by_server_resolve(client, conn, packet,
962                                              SILC_ID_CHANNEL, channel_id);
963         goto out;
964       }
965     }
966
967     /* Get the mode */
968     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
969     if (!tmp)
970       goto out;
971
972     SILC_GET32_MSB(mode, tmp);
973
974     /* If information is being resolved for this channel, wait for it */
975     if (channel->resolve_cmd_ident) {
976       silc_client_channel_wait(client, conn, channel, packet);
977       goto out;
978     }
979
980     /* Get target Client ID */
981     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
982     if (!tmp)
983       goto out;
984
985     silc_free(client_id);
986     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
987     if (!client_id)
988       goto out;
989
990     /* Find target Client entry */
991     client_entry2 =
992       silc_client_get_client_by_id(client, conn, client_id);
993     if (!client_entry2) {
994       silc_client_notify_by_server_resolve(client, conn, packet,
995                                            SILC_ID_CLIENT, client_id);
996       goto out;
997     }
998
999     /* Save the mode */
1000     chu = silc_client_on_channel(channel, client_entry2);
1001     if (chu)
1002       chu->mode = mode;
1003
1004     /* Notify application. The channel entry is sent last as this notify
1005        is for channel but application don't know it from the arguments
1006        sent by server. */
1007     client->internal->ops->notify(client, conn, type,
1008                                   id_type, client_entry, mode,
1009                                   client_entry2, channel);
1010     break;
1011
1012   case SILC_NOTIFY_TYPE_MOTD:
1013     /*
1014      * Received Message of the day
1015      */
1016
1017     SILC_LOG_DEBUG(("Notify: MOTD"));
1018
1019     /* Get motd */
1020     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1021     if (!tmp)
1022       goto out;
1023
1024     /* Notify application */
1025     client->internal->ops->notify(client, conn, type, tmp);
1026     break;
1027
1028   case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1029     /*
1030      * Router has enforced a new ID to a channel. Let's change the old
1031      * ID to the one provided here.
1032      */
1033
1034     SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1035
1036     /* Get the old ID */
1037     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1038     if (!tmp)
1039       goto out;
1040     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1041     if (!channel_id)
1042       goto out;
1043
1044     /* Get the channel entry */
1045     channel = silc_client_get_channel_by_id(client, conn, channel_id);
1046     if (!channel)
1047       goto out;
1048
1049     silc_free(channel_id);
1050     channel_id = NULL;
1051
1052     /* Get the new ID */
1053     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1054     if (!tmp)
1055       goto out;
1056     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1057     if (!channel_id)
1058       goto out;
1059
1060     /* Replace the Channel ID */
1061     if (silc_client_replace_channel_id(client, conn, channel, channel_id))
1062       channel_id = NULL;
1063
1064     /* Notify application */
1065     client->internal->ops->notify(client, conn, type, channel, channel);
1066     break;
1067
1068   case SILC_NOTIFY_TYPE_KICKED:
1069     /*
1070      * A client (maybe me) was kicked from a channel
1071      */
1072
1073     SILC_LOG_DEBUG(("Notify: KICKED"));
1074
1075     /* Get Client ID */
1076     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1077     if (!tmp)
1078       goto out;
1079
1080     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1081     if (!client_id)
1082       goto out;
1083
1084     /* Find Client entry */
1085     client_entry = silc_client_get_client_by_id(client, conn, client_id);
1086     if (!client_entry)
1087       goto out;
1088
1089     /* Get channel entry */
1090     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1091                                 SILC_ID_CHANNEL);
1092     if (!channel_id)
1093       goto out;
1094     channel = silc_client_get_channel_by_id(client, conn, channel_id);
1095     if (!channel)
1096       break;
1097
1098     /* From protocol version 1.1 we get the kicker's client ID as well */
1099     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1100     if (tmp) {
1101       silc_free(client_id);
1102       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1103       if (!client_id)
1104         goto out;
1105
1106       /* Find kicker's client entry and if not found resolve it */
1107       client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
1108       if (!client_entry2) {
1109         silc_client_notify_by_server_resolve(client, conn, packet,
1110                                              SILC_ID_CLIENT, client_id);
1111         goto out;
1112       } else {
1113         if (client_entry2 != conn->local_entry)
1114           silc_client_nickname_format(client, conn, client_entry2);
1115       }
1116     }
1117
1118     /* Get comment */
1119     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1120
1121     /* Notify application. The channel entry is sent last as this notify
1122        is for channel but application don't know it from the arguments
1123        sent by server. */
1124     client->internal->ops->notify(client, conn, type, client_entry, tmp,
1125                                   client_entry2, channel);
1126
1127     /* Remove kicked client from channel */
1128     if (client_entry == conn->local_entry) {
1129       /* If I was kicked from channel, remove the channel */
1130       if (conn->current_channel == channel)
1131         conn->current_channel = NULL;
1132       silc_client_del_channel(client, conn, channel);
1133     } else {
1134       chu = silc_client_on_channel(channel, client_entry);
1135       if (chu) {
1136         silc_hash_table_del(client_entry->channels, channel);
1137         silc_hash_table_del(channel->user_list, client_entry);
1138         silc_free(chu);
1139       }
1140
1141       if (!silc_hash_table_count(client_entry->channels)) {
1142         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1143         res->context = client;
1144         res->sock = silc_socket_dup(conn->sock);
1145         res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1146         silc_schedule_task_add(client->schedule, conn->sock->sock,
1147                                silc_client_notify_check_client, res,
1148                                (5 + (silc_rng_get_rn16(client->rng) % 529)),
1149                                0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1150       }
1151     }
1152     break;
1153
1154   case SILC_NOTIFY_TYPE_KILLED:
1155     {
1156       /*
1157        * A client (maybe me) was killed from the network.
1158        */
1159       char *comment;
1160       SilcUInt32 comment_len;
1161
1162       SILC_LOG_DEBUG(("Notify: KILLED"));
1163
1164       /* Get Client ID */
1165       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1166       if (!tmp)
1167         goto out;
1168
1169       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1170       if (!client_id)
1171         goto out;
1172
1173       /* Find Client entry */
1174       client_entry = silc_client_get_client_by_id(client, conn, client_id);
1175       if (!client_entry)
1176         goto out;
1177
1178       /* Get comment */
1179       comment = silc_argument_get_arg_type(args, 2, &comment_len);
1180
1181       /* From protocol version 1.1 we get killer's client ID as well */
1182       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1183       if (tmp) {
1184         silc_free(client_id);
1185         client_id = NULL;
1186         id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1187         if (!id)
1188           goto out;
1189
1190         /* Find Client entry */
1191         if (id_type == SILC_ID_CLIENT) {
1192           /* Find Client entry */
1193           client_id = id;
1194           client_entry2 = silc_client_get_client_by_id(client, conn,
1195                                                        client_id);
1196           if (!client_entry) {
1197             silc_client_notify_by_server_resolve(client, conn, packet,
1198                                                  SILC_ID_CLIENT, client_id);
1199             goto out;
1200           }
1201         } else if (id_type == SILC_ID_SERVER) {
1202           /* Find Server entry */
1203           server_id = id;
1204           server = silc_client_get_server_by_id(client, conn, server_id);
1205           if (!server) {
1206             silc_client_notify_by_server_resolve(client, conn, packet,
1207                                                  SILC_ID_SERVER, server_id);
1208             server = silc_client_add_server(client, conn, NULL, NULL,
1209                                             server_id);
1210             if (!server)
1211               goto out;
1212
1213             server->resolve_cmd_ident = conn->cmd_ident;
1214             server_id = NULL;
1215             goto out;
1216           }
1217
1218           if (server->resolve_cmd_ident) {
1219             SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1220             res->packet = silc_packet_context_dup(packet);
1221             res->context = client;
1222             res->sock = silc_socket_dup(conn->sock);
1223             silc_client_command_pending(conn, SILC_COMMAND_NONE,
1224                                         server->resolve_cmd_ident,
1225                                         silc_client_notify_by_server_pending,
1226                                         res);
1227             goto out;
1228           }
1229
1230           /* Save the pointer to the client_entry pointer */
1231           client_entry2 = (SilcClientEntry)server;
1232         } else {
1233           /* Find Channel entry */
1234           channel_id = id;
1235           channel = silc_client_get_channel_by_id(client, conn, channel_id);
1236           if (!channel) {
1237             silc_client_notify_by_server_resolve(client, conn, packet,
1238                                                  SILC_ID_CHANNEL, channel_id);
1239             goto out;
1240           }
1241
1242           /* Save the pointer to the client_entry pointer */
1243           client_entry2 = (SilcClientEntry)channel;
1244           silc_free(channel_id);
1245           channel_id = NULL;
1246         }
1247       }
1248
1249       /* Notify application. */
1250       client->internal->ops->notify(client, conn, type, client_entry,
1251                                     comment, id_type, client_entry2);
1252
1253       if (client_entry != conn->local_entry)
1254         /* Remove the client from all channels and free it */
1255         silc_client_del_client(client, conn, client_entry);
1256     }
1257     break;
1258
1259   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1260     {
1261       /*
1262        * A server quit the SILC network and some clients must be removed
1263        * from channels as they quit as well.
1264        */
1265       SilcClientEntry *clients = NULL;
1266       SilcUInt32 clients_count = 0;
1267       int i;
1268
1269       SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1270
1271       for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1272         /* Get Client ID */
1273         tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1274         if (tmp) {
1275           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1276           if (!client_id)
1277             goto out;
1278
1279           /* Get the client entry */
1280           client_entry = silc_client_get_client_by_id(client, conn, client_id);
1281           if (client_entry) {
1282             clients = silc_realloc(clients, sizeof(*clients) *
1283                                    (clients_count + 1));
1284             clients[clients_count] = client_entry;
1285             clients_count++;
1286           }
1287           silc_free(client_id);
1288         }
1289       }
1290       client_id = NULL;
1291
1292       /* Notify application. We don't keep server entries so the server
1293          entry is returned as NULL. The client's are returned as array
1294          of SilcClientEntry pointers. */
1295       client->internal->ops->notify(client, conn, type, NULL,
1296                                     clients, clients_count);
1297
1298       for (i = 0; i < clients_count; i++) {
1299         /* Remove client from all channels */
1300         client_entry = clients[i];
1301         if (client_entry == conn->local_entry)
1302           continue;
1303
1304         /* Remove the client from all channels and free it */
1305         silc_client_del_client(client, conn, client_entry);
1306       }
1307       silc_free(clients);
1308
1309     }
1310     break;
1311
1312   case SILC_NOTIFY_TYPE_ERROR:
1313     {
1314       /*
1315        * Some has occurred and server is notifying us about it.
1316        */
1317       SilcStatus error;
1318
1319       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1320       if (!tmp && tmp_len != 1)
1321         goto out;
1322       error = (SilcStatus)tmp[0];
1323
1324       SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1325
1326       if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1327         tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1328         if (tmp) {
1329           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1330           if (!client_id)
1331             goto out;
1332           client_entry = silc_client_get_client_by_id(client, conn,
1333                                                       client_id);
1334           if (client_entry)
1335             silc_client_del_client(client, conn, client_entry);
1336         }
1337       }
1338
1339       /* Notify application. */
1340       client->internal->ops->notify(client, conn, type, error);
1341     }
1342     break;
1343
1344   case SILC_NOTIFY_TYPE_WATCH:
1345     {
1346       /*
1347        * Received notify about some client we are watching
1348        */
1349       SilcNotifyType notify = 0;
1350       bool del_client = FALSE;
1351
1352       SILC_LOG_DEBUG(("Notify: WATCH"));
1353
1354       /* Get sender Client ID */
1355       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1356       if (!tmp)
1357         goto out;
1358       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1359       if (!client_id)
1360         goto out;
1361
1362       /* Find Client entry and if not found query it */
1363       client_entry = silc_client_get_client_by_id(client, conn, client_id);
1364       if (!client_entry) {
1365         silc_client_notify_by_server_resolve(client, conn, packet,
1366                                              SILC_ID_CLIENT, client_id);
1367         goto out;
1368       }
1369
1370       /* Get user mode */
1371       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1372       if (!tmp || tmp_len != 4)
1373         goto out;
1374       SILC_GET32_MSB(mode, tmp);
1375
1376       /* Get notify type */
1377       tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1378       if (tmp && tmp_len != 2)
1379         goto out;
1380       if (tmp)
1381         SILC_GET16_MSB(notify, tmp);
1382
1383       /* Get nickname */
1384       tmp = silc_argument_get_arg_type(args, 2, NULL);
1385       if (tmp) {
1386         char *tmp_nick = NULL;
1387
1388         if (client->internal->params->nickname_parse)
1389           client->internal->params->nickname_parse(client_entry->nickname,
1390                                                    &tmp_nick);
1391         else
1392           tmp_nick = strdup(tmp);
1393
1394         /* If same nick, the client was new to us and has become "present"
1395            to network.  Send NULL as nick to application. */
1396         if (tmp_nick && !strcmp(tmp, tmp_nick))
1397           tmp = NULL;
1398
1399         silc_free(tmp_nick);
1400       }
1401
1402       /* Notify application. */
1403       client->internal->ops->notify(client, conn, type, client_entry,
1404                                     tmp, mode, notify);
1405
1406       client_entry->mode = mode;
1407
1408       /* If nickname was changed, remove the client entry unless the
1409          client is on some channel */
1410       if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1411           !silc_hash_table_count(client_entry->channels))
1412         del_client = TRUE;
1413       else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1414                notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1415                notify == SILC_NOTIFY_TYPE_KILLED)
1416         del_client = TRUE;
1417
1418       if (del_client) {
1419         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1420         res->context = client;
1421         res->sock = silc_socket_dup(conn->sock);
1422         res->packet = client_id;
1423         client_id = NULL;
1424         silc_schedule_task_add(client->schedule, conn->sock->sock,
1425                                silc_client_notify_del_client_cb, res,
1426                                1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1427       }
1428     }
1429     break;
1430
1431   default:
1432     break;
1433   }
1434
1435  out:
1436   silc_notify_payload_free(payload);
1437   silc_free(client_id);
1438   silc_free(channel_id);
1439   silc_free(server_id);
1440 }