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