Remove client from channel before calling KICKED notify to app.
[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     /* Get signoff message */
448     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
449     if (tmp_len > 128)
450       tmp = NULL;
451
452     /* Notify application */
453     client->internal->ops->notify(client, conn, type, client_entry, tmp);
454
455     /* Remove from all channels */
456     silc_client_remove_from_channels(client, conn, client_entry);
457
458     /* Remove from cache */
459     silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
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     /* Remove kicked client from channel */
1122     if (client_entry != conn->local_entry) {
1123       chu = silc_client_on_channel(channel, client_entry);
1124       if (chu) {
1125         silc_hash_table_del(client_entry->channels, channel);
1126         silc_hash_table_del(channel->user_list, client_entry);
1127         silc_free(chu);
1128       }
1129     }
1130
1131     /* Notify application. The channel entry is sent last as this notify
1132        is for channel but application don't know it from the arguments
1133        sent by server. */
1134     client->internal->ops->notify(client, conn, type, client_entry, tmp,
1135                                   client_entry2, channel);
1136
1137     /* Remove kicked client (us) from channel */
1138     if (client_entry == conn->local_entry) {
1139       /* If I was kicked from channel, remove the channel */
1140       if (conn->current_channel == channel)
1141         conn->current_channel = NULL;
1142       silc_client_del_channel(client, conn, channel);
1143     } else {
1144       if (!silc_hash_table_count(client_entry->channels)) {
1145         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1146         res->context = client;
1147         res->sock = silc_socket_dup(conn->sock);
1148         res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1149         silc_schedule_task_add(client->schedule, conn->sock->sock,
1150                                silc_client_notify_check_client, res,
1151                                (5 + (silc_rng_get_rn16(client->rng) % 529)),
1152                                0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1153       }
1154     }
1155     break;
1156
1157   case SILC_NOTIFY_TYPE_KILLED:
1158     {
1159       /*
1160        * A client (maybe me) was killed from the network.
1161        */
1162       char *comment;
1163       SilcUInt32 comment_len;
1164
1165       SILC_LOG_DEBUG(("Notify: KILLED"));
1166
1167       /* Get Client ID */
1168       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1169       if (!tmp)
1170         goto out;
1171
1172       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1173       if (!client_id)
1174         goto out;
1175
1176       /* Find Client entry */
1177       client_entry = silc_client_get_client_by_id(client, conn, client_id);
1178       if (!client_entry)
1179         goto out;
1180
1181       /* Get comment */
1182       comment = silc_argument_get_arg_type(args, 2, &comment_len);
1183
1184       /* From protocol version 1.1 we get killer's client ID as well */
1185       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1186       if (tmp) {
1187         silc_free(client_id);
1188         client_id = NULL;
1189         id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1190         if (!id)
1191           goto out;
1192
1193         /* Find Client entry */
1194         if (id_type == SILC_ID_CLIENT) {
1195           /* Find Client entry */
1196           client_id = id;
1197           client_entry2 = silc_client_get_client_by_id(client, conn,
1198                                                        client_id);
1199           if (!client_entry) {
1200             silc_client_notify_by_server_resolve(client, conn, packet,
1201                                                  SILC_ID_CLIENT, client_id);
1202             goto out;
1203           }
1204         } else if (id_type == SILC_ID_SERVER) {
1205           /* Find Server entry */
1206           server_id = id;
1207           server = silc_client_get_server_by_id(client, conn, server_id);
1208           if (!server) {
1209             silc_client_notify_by_server_resolve(client, conn, packet,
1210                                                  SILC_ID_SERVER, server_id);
1211             server = silc_client_add_server(client, conn, NULL, NULL,
1212                                             server_id);
1213             if (!server)
1214               goto out;
1215
1216             server->resolve_cmd_ident = conn->cmd_ident;
1217             server_id = NULL;
1218             goto out;
1219           }
1220
1221           if (server->resolve_cmd_ident) {
1222             SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1223             res->packet = silc_packet_context_dup(packet);
1224             res->context = client;
1225             res->sock = silc_socket_dup(conn->sock);
1226             silc_client_command_pending(conn, SILC_COMMAND_NONE,
1227                                         server->resolve_cmd_ident,
1228                                         silc_client_notify_by_server_pending,
1229                                         res);
1230             goto out;
1231           }
1232
1233           /* Save the pointer to the client_entry pointer */
1234           client_entry2 = (SilcClientEntry)server;
1235         } else {
1236           /* Find Channel entry */
1237           channel_id = id;
1238           channel = silc_client_get_channel_by_id(client, conn, channel_id);
1239           if (!channel) {
1240             silc_client_notify_by_server_resolve(client, conn, packet,
1241                                                  SILC_ID_CHANNEL, channel_id);
1242             goto out;
1243           }
1244
1245           /* Save the pointer to the client_entry pointer */
1246           client_entry2 = (SilcClientEntry)channel;
1247           silc_free(channel_id);
1248           channel_id = NULL;
1249         }
1250       }
1251
1252       /* Notify application. */
1253       client->internal->ops->notify(client, conn, type, client_entry,
1254                                     comment, id_type, client_entry2);
1255
1256       if (client_entry != conn->local_entry)
1257         /* Remove the client from all channels and free it */
1258         silc_client_del_client(client, conn, client_entry);
1259     }
1260     break;
1261
1262   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1263     {
1264       /*
1265        * A server quit the SILC network and some clients must be removed
1266        * from channels as they quit as well.
1267        */
1268       SilcClientEntry *clients = NULL;
1269       SilcUInt32 clients_count = 0;
1270       int i;
1271
1272       SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1273
1274       for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1275         /* Get Client ID */
1276         tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1277         if (tmp) {
1278           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1279           if (!client_id)
1280             goto out;
1281
1282           /* Get the client entry */
1283           client_entry = silc_client_get_client_by_id(client, conn, client_id);
1284           if (client_entry) {
1285             clients = silc_realloc(clients, sizeof(*clients) *
1286                                    (clients_count + 1));
1287             clients[clients_count] = client_entry;
1288             clients_count++;
1289           }
1290           silc_free(client_id);
1291         }
1292       }
1293       client_id = NULL;
1294
1295       /* Notify application. We don't keep server entries so the server
1296          entry is returned as NULL. The client's are returned as array
1297          of SilcClientEntry pointers. */
1298       client->internal->ops->notify(client, conn, type, NULL,
1299                                     clients, clients_count);
1300
1301       for (i = 0; i < clients_count; i++) {
1302         /* Remove client from all channels */
1303         client_entry = clients[i];
1304         if (client_entry == conn->local_entry)
1305           continue;
1306
1307         /* Remove the client from all channels and free it */
1308         silc_client_del_client(client, conn, client_entry);
1309       }
1310       silc_free(clients);
1311
1312     }
1313     break;
1314
1315   case SILC_NOTIFY_TYPE_ERROR:
1316     {
1317       /*
1318        * Some has occurred and server is notifying us about it.
1319        */
1320       SilcStatus error;
1321
1322       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1323       if (!tmp && tmp_len != 1)
1324         goto out;
1325       error = (SilcStatus)tmp[0];
1326
1327       SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1328
1329       if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1330         tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1331         if (tmp) {
1332           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1333           if (!client_id)
1334             goto out;
1335           client_entry = silc_client_get_client_by_id(client, conn,
1336                                                       client_id);
1337           if (client_entry)
1338             silc_client_del_client(client, conn, client_entry);
1339         }
1340       }
1341
1342       /* Notify application. */
1343       client->internal->ops->notify(client, conn, type, error);
1344     }
1345     break;
1346
1347   case SILC_NOTIFY_TYPE_WATCH:
1348     {
1349       /*
1350        * Received notify about some client we are watching
1351        */
1352       SilcNotifyType notify = 0;
1353       bool del_client = FALSE;
1354
1355       SILC_LOG_DEBUG(("Notify: WATCH"));
1356
1357       /* Get sender Client ID */
1358       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1359       if (!tmp)
1360         goto out;
1361       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1362       if (!client_id)
1363         goto out;
1364
1365       /* Find Client entry and if not found query it */
1366       client_entry = silc_client_get_client_by_id(client, conn, client_id);
1367       if (!client_entry) {
1368         silc_client_notify_by_server_resolve(client, conn, packet,
1369                                              SILC_ID_CLIENT, client_id);
1370         goto out;
1371       }
1372
1373       /* Get user mode */
1374       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1375       if (!tmp || tmp_len != 4)
1376         goto out;
1377       SILC_GET32_MSB(mode, tmp);
1378
1379       /* Get notify type */
1380       tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1381       if (tmp && tmp_len != 2)
1382         goto out;
1383       if (tmp)
1384         SILC_GET16_MSB(notify, tmp);
1385
1386       /* Get nickname */
1387       tmp = silc_argument_get_arg_type(args, 2, NULL);
1388       if (tmp) {
1389         char *tmp_nick = NULL;
1390
1391         if (client->internal->params->nickname_parse)
1392           client->internal->params->nickname_parse(client_entry->nickname,
1393                                                    &tmp_nick);
1394         else
1395           tmp_nick = strdup(tmp);
1396
1397         /* If same nick, the client was new to us and has become "present"
1398            to network.  Send NULL as nick to application. */
1399         if (tmp_nick && !strcmp(tmp, tmp_nick))
1400           tmp = NULL;
1401
1402         silc_free(tmp_nick);
1403       }
1404
1405       /* Notify application. */
1406       client->internal->ops->notify(client, conn, type, client_entry,
1407                                     tmp, mode, notify);
1408
1409       client_entry->mode = mode;
1410
1411       /* If nickname was changed, remove the client entry unless the
1412          client is on some channel */
1413       if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1414           !silc_hash_table_count(client_entry->channels))
1415         del_client = TRUE;
1416       else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1417                notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1418                notify == SILC_NOTIFY_TYPE_KILLED)
1419         del_client = TRUE;
1420
1421       if (del_client) {
1422         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1423         res->context = client;
1424         res->sock = silc_socket_dup(conn->sock);
1425         res->packet = client_id;
1426         client_id = NULL;
1427         silc_schedule_task_add(client->schedule, conn->sock->sock,
1428                                silc_client_notify_del_client_cb, res,
1429                                1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1430       }
1431     }
1432     break;
1433
1434   default:
1435     break;
1436   }
1437
1438  out:
1439   silc_notify_payload_free(payload);
1440   silc_free(client_id);
1441   silc_free(channel_id);
1442   silc_free(server_id);
1443 }