Initial client library rewrite, connects to remote server already.
[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 - 2006 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
21 #include "silc.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
24
25 /* Context used for resolving client, channel and server info. */
26 typedef struct {
27   void *packet;
28   void *context;
29   SilcSocketConnection sock;
30 } *SilcClientNotifyResolve;
31
32 SILC_TASK_CALLBACK(silc_client_notify_check_client)
33 {
34   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
35   SilcClient client = res->context;
36   SilcClientConnection conn = res->sock->user_data;
37   SilcClientID *client_id = res->packet;
38   silc_client_get_client_by_id_resolve(client, conn, client_id,
39                                        NULL, NULL, NULL);
40   silc_free(client_id);
41   silc_socket_free(res->sock);
42   silc_free(res);
43 }
44
45 SILC_TASK_CALLBACK(silc_client_notify_del_client_cb)
46 {
47   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
48   SilcClient client = res->context;
49   SilcClientConnection conn = res->sock->user_data;
50   SilcClientID *client_id = res->packet;
51   SilcClientEntry client_entry;
52   client_entry = silc_client_get_client_by_id(client, conn, client_id);
53   if (client_entry)
54     silc_client_del_client(client, conn, client_entry);
55   silc_free(client_id);
56   silc_socket_free(res->sock);
57   silc_free(res);
58 }
59
60 /* Called when notify is received and some async operation (such as command)
61    is required before processing the notify message. This calls again the
62    silc_client_notify_by_server and reprocesses the original notify packet. */
63
64 static void silc_client_notify_by_server_pending(void *context, void *context2)
65 {
66   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
67   SilcClientCommandReplyContext reply =
68     (SilcClientCommandReplyContext)context2;
69
70   SILC_LOG_DEBUG(("Start"));
71
72   if (reply && !silc_command_get_status(reply->payload, NULL, NULL))
73     goto out;
74
75   silc_client_notify_by_server(res->context, res->sock, res->packet);
76
77  out:
78   silc_socket_free(res->sock);
79   silc_packet_context_free(res->packet);
80   silc_free(res);
81 }
82
83 /* Resets the channel entry's resolve_cmd_ident after whatever-thing
84    was resolved is completed. */
85
86 static void silc_client_channel_cond(void *context, void *context2)
87 {
88   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
89   SilcClient client = res->context;
90   SilcClientConnection conn = res->sock->user_data;
91   SilcChannelID *channel_id = res->packet;
92   SilcChannelEntry channel;
93   channel = silc_client_get_channel_by_id(client, conn, channel_id);
94   if (channel)
95     channel->resolve_cmd_ident = 0;
96   silc_free(channel_id);
97   silc_socket_free(res->sock);
98   silc_free(res);
99 }
100
101 /* Function that starts waiting for the `cmd_ident' to arrive and
102    marks the channel info being resolved.  */
103
104 static void silc_client_channel_set_wait(SilcClient client,
105                                          SilcClientConnection conn,
106                                          SilcChannelEntry channel,
107                                          SilcUInt16 cmd_ident)
108 {
109   SilcClientNotifyResolve res;
110
111   if (!channel->resolve_cmd_ident) {
112     res = silc_calloc(1, sizeof(*res));
113     res->context = client;
114     res->sock = silc_socket_dup(conn->sock);
115     res->packet = silc_id_dup(channel->id, SILC_ID_CHANNEL);
116     silc_client_command_pending(conn, SILC_COMMAND_NONE, cmd_ident,
117                                 silc_client_channel_cond, res);
118     channel->resolve_cmd_ident = cmd_ident;
119   }
120 }
121
122 /* Attaches to the channel's resolving cmd ident and calls the
123    notify handling with `packet' after it's received. */
124
125 static void silc_client_channel_wait(SilcClient client,
126                                      SilcClientConnection conn,
127                                      SilcChannelEntry channel,
128                                      SilcPacketContext *packet)
129 {
130   SilcClientNotifyResolve res;
131
132   if (!channel->resolve_cmd_ident)
133     return;
134
135   res = silc_calloc(1, sizeof(*res));
136   res->packet = silc_packet_context_dup(packet);
137   res->context = client;
138   res->sock = silc_socket_dup(conn->sock);
139
140   silc_client_command_pending(conn, SILC_COMMAND_NONE,
141                               channel->resolve_cmd_ident,
142                               silc_client_notify_by_server_pending, res);
143 }
144
145 /* Resolve client, channel or server information. */
146
147 static void silc_client_notify_by_server_resolve(SilcClient client,
148                                                  SilcClientConnection conn,
149                                                  SilcPacketContext *packet,
150                                                  SilcIdType id_type,
151                                                  void *id)
152 {
153   SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
154   SilcBuffer idp = silc_id_payload_encode(id, id_type);
155
156   res->packet = silc_packet_context_dup(packet);
157   res->context = client;
158   res->sock = silc_socket_dup(conn->sock);
159
160   /* For client resolving use WHOIS, and otherwise use IDENTIFY */
161   if (id_type == SILC_ID_CLIENT) {
162     silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
163                                  silc_client_command_reply_whois_i, 0,
164                                  ++conn->cmd_ident);
165     silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
166                              1, 4, idp->data, idp->len);
167     silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
168                                 silc_client_notify_by_server_pending, res);
169   } else {
170     silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
171                                  silc_client_command_reply_identify_i, 0,
172                                  ++conn->cmd_ident);
173     silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
174                              conn->cmd_ident, 1, 5, idp->data, idp->len);
175     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
176                                 silc_client_notify_by_server_pending, res);
177   }
178   silc_buffer_free(idp);
179 }
180
181 /* Received notify message from server */
182
183 void silc_client_notify_by_server(SilcClient client,
184                                   SilcSocketConnection sock,
185                                   SilcPacketContext *packet)
186 {
187   SilcBuffer buffer = packet->buffer;
188   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
189   SilcNotifyPayload payload;
190   SilcNotifyType type;
191   SilcArgumentPayload args;
192
193   void *id;
194   SilcIdType id_type;
195   SilcClientID *client_id = NULL;
196   SilcChannelID *channel_id = NULL;
197   SilcServerID *server_id = NULL;
198   SilcClientEntry client_entry = NULL;
199   SilcClientEntry client_entry2 = NULL;
200   SilcChannelEntry channel;
201   SilcChannelUser chu;
202   SilcServerEntry server;
203   unsigned char *tmp;
204   SilcUInt32 tmp_len, mode;
205
206   SILC_LOG_DEBUG(("Start"));
207
208   payload = silc_notify_payload_parse(buffer->data, buffer->len);
209   if (!payload)
210     goto out;
211
212   type = silc_notify_get_type(payload);
213   args = silc_notify_get_args(payload);
214   if (!args)
215     goto out;
216
217   switch(type) {
218   case SILC_NOTIFY_TYPE_NONE:
219     /* Notify application */
220     client->internal->ops->notify(client, conn, type,
221                                   silc_argument_get_arg_type(args, 1, NULL));
222     break;
223
224   case SILC_NOTIFY_TYPE_INVITE:
225     /*
226      * Someone invited me to a channel. Find Client and Channel entries
227      * for the application.
228      */
229
230     SILC_LOG_DEBUG(("Notify: INVITE"));
231
232     /* Get Channel ID */
233     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
234     if (!tmp)
235       goto out;
236
237     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
238     if (!channel_id)
239       goto out;
240
241     /* Get the channel entry */
242     channel = silc_client_get_channel_by_id(client, conn, channel_id);
243
244     /* Get sender Client ID */
245     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
246     if (!tmp)
247       goto out;
248
249     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
250     if (!client_id)
251       goto out;
252
253     /* Find Client entry and if not found query it */
254     client_entry = silc_client_get_client_by_id(client, conn, client_id);
255     if (!client_entry) {
256       silc_client_notify_by_server_resolve(client, conn, packet,
257                                            SILC_ID_CLIENT, client_id);
258       goto out;
259     }
260
261     /* Get the channel name */
262     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
263     if (!tmp)
264       goto out;
265
266     /* Notify application */
267     client->internal->ops->notify(client, conn, type, channel, tmp,
268                                   client_entry);
269     break;
270
271   case SILC_NOTIFY_TYPE_JOIN:
272     /*
273      * Someone has joined to a channel. Get their ID and nickname and
274      * cache them for later use.
275      */
276
277     SILC_LOG_DEBUG(("Notify: JOIN"));
278
279     /* Get Channel ID */
280     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
281     if (!tmp)
282       goto out;
283
284     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
285     if (!channel_id)
286       goto out;
287
288     /* Get channel entry */
289     channel = silc_client_get_channel_by_id(client, conn, channel_id);
290     if (!channel)
291       break;
292
293     /* Get Client ID */
294     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
295     if (!tmp)
296       goto out;
297
298     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
299     if (!client_id)
300       goto out;
301
302     /* Find Client entry and if not found query it */
303     client_entry = silc_client_get_client_by_id(client, conn, client_id);
304     if (!client_entry) {
305       silc_client_channel_set_wait(client, conn, channel,
306                                    conn->cmd_ident + 1);
307       silc_client_notify_by_server_resolve(client, conn, packet,
308                                            SILC_ID_CLIENT, client_id);
309       goto out;
310     }
311
312     /* If nickname or username hasn't been resolved, do so */
313     if (!client_entry->nickname || !client_entry->username) {
314       if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
315         /* Attach to existing resolving */
316         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
317         res->packet = silc_packet_context_dup(packet);
318         res->context = client;
319         res->sock = silc_socket_dup(conn->sock);
320         silc_client_command_pending(conn, SILC_COMMAND_NONE,
321                                     client_entry->resolve_cmd_ident,
322                                     silc_client_notify_by_server_pending,
323                                     res);
324         goto out;
325       }
326
327       /* Do new resolving */
328       silc_client_channel_set_wait(client, conn, channel,
329                                    conn->cmd_ident + 1);
330       silc_client_notify_by_server_resolve(client, conn, packet,
331                                            SILC_ID_CLIENT, client_id);
332       client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
333       client_entry->resolve_cmd_ident = conn->cmd_ident;
334       goto out;
335     } else {
336       if (client_entry != conn->local_entry)
337         silc_client_nickname_format(client, conn, client_entry);
338     }
339
340     /* If information is being resolved for this channel, wait for it */
341     if (channel->resolve_cmd_ident) {
342       silc_client_channel_wait(client, conn, channel, packet);
343       goto out;
344     }
345
346     /* Join the client to channel */
347     if (!silc_client_on_channel(channel, client_entry)) {
348       chu = silc_calloc(1, sizeof(*chu));
349       chu->client = client_entry;
350       chu->channel = channel;
351       silc_hash_table_add(channel->user_list, client_entry, chu);
352       silc_hash_table_add(client_entry->channels, channel, chu);
353     }
354
355     /* Notify application. The channel entry is sent last as this notify
356        is for channel but application don't know it from the arguments
357        sent by server. */
358     client->internal->ops->notify(client, conn, type, client_entry, channel);
359     break;
360
361   case SILC_NOTIFY_TYPE_LEAVE:
362     /*
363      * Someone has left a channel. We will remove it from the channel but
364      * we'll keep it in the cache in case we'll need it later.
365      */
366
367     SILC_LOG_DEBUG(("Notify: LEAVE"));
368
369     /* Get Client ID */
370     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
371     if (!tmp)
372       goto out;
373
374     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
375     if (!client_id)
376       goto out;
377
378     /* Find Client entry */
379     client_entry =
380       silc_client_get_client_by_id(client, conn, client_id);
381     if (!client_entry)
382       goto out;
383
384     /* Get channel entry */
385     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
386                                 SILC_ID_CHANNEL);
387     if (!channel_id)
388       goto out;
389     channel = silc_client_get_channel_by_id(client, conn, channel_id);
390     if (!channel)
391       break;
392
393     /* Remove client from channel */
394     chu = silc_client_on_channel(channel, client_entry);
395     if (chu) {
396       silc_hash_table_del(client_entry->channels, channel);
397       silc_hash_table_del(channel->user_list, client_entry);
398       silc_free(chu);
399     }
400
401     /* Some client implementations actually quit network by first doing
402        LEAVE and then immediately SIGNOFF.  We'll check for this by doing
403        check for the client after 5 - 34 seconds.  If it is not valid after
404        that we'll remove the client from cache. */
405     if (!silc_hash_table_count(client_entry->channels)) {
406       SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
407       res->context = client;
408       res->sock = silc_socket_dup(conn->sock);
409       res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
410       silc_schedule_task_add(client->schedule, conn->sock->sock,
411                              silc_client_notify_check_client, res,
412                              (5 + (silc_rng_get_rn16(client->rng) % 29)),
413                              0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
414     }
415
416     /* Notify application. The channel entry is sent last as this notify
417        is for channel but application don't know it from the arguments
418        sent by server. */
419     client->internal->ops->notify(client, conn, type, client_entry, channel);
420     break;
421
422   case SILC_NOTIFY_TYPE_SIGNOFF:
423     /*
424      * Someone left SILC. We'll remove it from all channels and from cache.
425      */
426
427     SILC_LOG_DEBUG(("Notify: SIGNOFF"));
428
429     /* Get Client ID */
430     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
431     if (!tmp)
432       goto out;
433
434     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
435     if (!client_id)
436       goto out;
437
438     /* Find Client entry */
439     client_entry =
440       silc_client_get_client_by_id(client, conn, client_id);
441     if (!client_entry)
442       goto out;
443
444     /* Get signoff message */
445     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
446     if (tmp_len > 128)
447       tmp = NULL;
448
449     /* Notify application */
450     client->internal->ops->notify(client, conn, type, client_entry, tmp);
451
452     /* Remove from all channels */
453     silc_client_remove_from_channels(client, conn, client_entry);
454
455     /* Remove from cache */
456     silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
457
458     /* Free data */
459     silc_client_del_client_entry(client, conn, client_entry);
460     break;
461
462   case SILC_NOTIFY_TYPE_TOPIC_SET:
463     /*
464      * Someone set the topic on a channel.
465      */
466
467     SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
468
469     /* Get channel entry */
470     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
471                                 SILC_ID_CHANNEL);
472     if (!channel_id)
473       goto out;
474     channel = silc_client_get_channel_by_id(client, conn, channel_id);
475     if (!channel)
476       break;
477
478     /* Get ID */
479     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
480     if (!tmp)
481       goto out;
482     id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
483     if (!id)
484       goto out;
485
486     /* Find Client entry */
487     if (id_type == SILC_ID_CLIENT) {
488       /* Find Client entry */
489       client_id = id;
490       client_entry = silc_client_get_client_by_id(client, conn, client_id);
491       if (!client_entry) {
492         silc_client_channel_set_wait(client, conn, channel,
493                                      conn->cmd_ident + 1);
494         silc_client_notify_by_server_resolve(client, conn, packet,
495                                              SILC_ID_CLIENT, client_id);
496         goto out;
497       }
498     } else if (id_type == SILC_ID_SERVER) {
499       /* Find Server entry */
500       server_id = id;
501       server = silc_client_get_server_by_id(client, conn, server_id);
502       if (!server) {
503         silc_client_channel_set_wait(client, conn, channel,
504                                      conn->cmd_ident + 1);
505         silc_client_notify_by_server_resolve(client, conn, packet,
506                                              SILC_ID_SERVER, server_id);
507         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
508         if (!server)
509           goto out;
510
511         server->resolve_cmd_ident = conn->cmd_ident;
512         server_id = NULL;
513         goto out;
514       }
515
516       /* If entry being resoled, wait for it before processing this notify */
517       if (server->resolve_cmd_ident) {
518         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
519         res->packet = silc_packet_context_dup(packet);
520         res->context = client;
521         res->sock = silc_socket_dup(conn->sock);
522         silc_client_command_pending(conn, SILC_COMMAND_NONE,
523                                     server->resolve_cmd_ident,
524                                     silc_client_notify_by_server_pending, res);
525         goto out;
526       }
527
528       /* Save the pointer to the client_entry pointer */
529       client_entry = (SilcClientEntry)server;
530     } else {
531       /* Find Channel entry */
532       silc_free(channel_id);
533       channel_id = id;
534       client_entry = (SilcClientEntry)
535         silc_client_get_channel_by_id(client, conn, channel_id);
536       if (!client_entry) {
537         silc_client_channel_set_wait(client, conn, channel,
538                                      conn->cmd_ident + 1);
539         silc_client_notify_by_server_resolve(client, conn, packet,
540                                              SILC_ID_CHANNEL, channel_id);
541         goto out;
542       }
543     }
544
545     /* Get topic */
546     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
547     if (!tmp)
548       goto out;
549
550     /* If information is being resolved for this channel, wait for it */
551     if (channel->resolve_cmd_ident) {
552       silc_client_channel_wait(client, conn, channel, packet);
553       goto out;
554     }
555
556     if (tmp) {
557       silc_free(channel->topic);
558       channel->topic = silc_memdup(tmp, strlen(tmp));
559     }
560
561     /* Notify application. The channel entry is sent last as this notify
562        is for channel but application don't know it from the arguments
563        sent by server. */
564     client->internal->ops->notify(client, conn, type, id_type,
565                                   client_entry, tmp, channel);
566
567     break;
568
569   case SILC_NOTIFY_TYPE_NICK_CHANGE:
570     /*
571      * Someone changed their nickname. If we don't have entry for the new
572      * ID we will query it and return here after it's done. After we've
573      * returned we fetch the old entry and free it and notify the
574      * application.
575      */
576
577     SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
578
579     /* Get old Client ID */
580     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
581     if (!tmp)
582       goto out;
583
584     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
585     if (!client_id)
586       goto out;
587
588     /* Ignore my ID */
589     if (conn->local_id && SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
590       break;
591
592     /* Find old Client entry */
593     client_entry = silc_client_get_client_by_id(client, conn, client_id);
594     if (!client_entry)
595       goto out;
596     silc_free(client_id);
597     client_id = NULL;
598
599     /* Wait for resolving if necessary */
600     if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
601       SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
602       res->packet = silc_packet_context_dup(packet);
603       res->context = client;
604       res->sock = silc_socket_dup(conn->sock);
605       silc_client_command_pending(conn, SILC_COMMAND_NONE,
606                                   client_entry->resolve_cmd_ident,
607                                   silc_client_notify_by_server_pending, res);
608       goto out;
609     }
610
611     client_entry->valid = FALSE;
612
613     /* Get new Client ID */
614     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
615     if (!tmp)
616       goto out;
617
618     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
619     if (!client_id)
620       goto out;
621
622     /* Take the nickname */
623     tmp = silc_argument_get_arg_type(args, 3, NULL);
624     if (!tmp)
625       goto out;
626
627     /* Check whether nickname changed at all.  It is possible that nick
628        change notify is received but nickname didn't change, only the
629        ID changes.  Check whether the hashes in the Client ID match, if
630        they do nickname didn't change. */
631     if (SILC_ID_COMPARE_HASH(client_entry->id, client_id) &&
632         silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
633       /* Nickname didn't change.  Update only Client ID. */
634
635       /* Normalize nickname */
636       tmp = silc_identifier_check(tmp, strlen(tmp),
637                                   SILC_STRING_UTF8, 128, NULL);
638       if (!tmp)
639         goto out;
640
641       silc_idcache_del_by_context(conn->internal->client_cache,
642                                   client_entry);
643       silc_free(client_entry->id);
644       client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
645       silc_idcache_add(conn->internal->client_cache, tmp,
646                        client_entry->id, client_entry, 0, NULL);
647
648       /* Notify application */
649       client->internal->ops->notify(client, conn, type,
650                                     client_entry, client_entry);
651       break;
652     }
653
654     /* Create new client entry, and save all old information with the
655        new nickname and client ID */
656     client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
657                                            client_entry->realname,
658                                            silc_id_dup(client_id,
659                                                        SILC_ID_CLIENT), 0);
660     if (!client_entry2)
661       goto out;
662
663     if (client_entry->server)
664       client_entry2->server = strdup(client_entry->server);
665     if (client_entry->username)
666       client_entry2->username = strdup(client_entry->username);
667     if (client_entry->hostname)
668       client_entry2->hostname = strdup(client_entry->hostname);
669     client_entry2->fingerprint = client_entry->fingerprint;
670     client_entry2->fingerprint_len = client_entry->fingerprint_len;
671     client_entry->fingerprint = NULL;
672     client_entry->fingerprint_len = 0;
673     silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
674                               client_entry->mode);
675
676     /* Remove the old from cache */
677     silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
678
679     /* Replace old ID entry with new one on all channels. */
680     silc_client_replace_from_channels(client, conn, client_entry,
681                                       client_entry2);
682
683     /* Notify application */
684     client->internal->ops->notify(client, conn, type,
685                                   client_entry, client_entry2);
686
687     /* Free old client entry */
688     silc_client_del_client_entry(client, conn, client_entry);
689
690     break;
691
692   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
693     {
694       /*
695        * Someone changed a channel mode
696        */
697       char *passphrase, *cipher, *hmac;
698       SilcPublicKey founder_key = NULL;
699       SilcBufferStruct chpks;
700
701       SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
702
703       /* Get channel entry */
704       channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
705                                   SILC_ID_CHANNEL);
706       if (!channel_id)
707         goto out;
708       channel = silc_client_get_channel_by_id(client, conn, channel_id);
709       if (!channel)
710         goto out;
711
712       /* Get ID */
713       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
714       if (!tmp)
715         goto out;
716       id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
717       if (!id)
718         goto out;
719
720       /* Find Client entry */
721       if (id_type == SILC_ID_CLIENT) {
722         /* Find Client entry */
723         client_id = id;
724         client_entry = silc_client_get_client_by_id(client, conn, client_id);
725         if (!client_entry) {
726           silc_client_channel_set_wait(client, conn, channel,
727                                        conn->cmd_ident + 1);
728           silc_client_notify_by_server_resolve(client, conn, packet,
729                                                SILC_ID_CLIENT, client_id);
730           goto out;
731         }
732
733         if (!client_entry->nickname) {
734           if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
735             /* Attach to existing resolving */
736             SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
737             res->packet = silc_packet_context_dup(packet);
738             res->context = client;
739             res->sock = silc_socket_dup(conn->sock);
740             silc_client_command_pending(conn, SILC_COMMAND_NONE,
741                                         client_entry->resolve_cmd_ident,
742                                         silc_client_notify_by_server_pending,
743                                         res);
744             goto out;
745           }
746
747           /* Do new resolving */
748           silc_client_channel_set_wait(client, conn, channel,
749                                        conn->cmd_ident + 1);
750           silc_client_notify_by_server_resolve(client, conn, packet,
751                                                SILC_ID_CLIENT, client_id);
752           client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
753           client_entry->resolve_cmd_ident = conn->cmd_ident;
754           goto out;
755         }
756       } else if (id_type == SILC_ID_SERVER) {
757         /* Find Server entry */
758         server_id = id;
759         server = silc_client_get_server_by_id(client, conn, server_id);
760         if (!server) {
761           silc_client_channel_set_wait(client, conn, channel,
762                                        conn->cmd_ident + 1);
763           silc_client_notify_by_server_resolve(client, conn, packet,
764                                                SILC_ID_SERVER, server_id);
765           server = silc_client_add_server(client, conn, NULL, NULL, server_id);
766           if (!server)
767             goto out;
768
769           server->resolve_cmd_ident = conn->cmd_ident;
770           server_id = NULL;
771           goto out;
772         }
773
774         /* If entry being resoled, wait for it before processing this notify */
775         if (server->resolve_cmd_ident) {
776           SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
777           res->packet = silc_packet_context_dup(packet);
778           res->context = client;
779           res->sock = silc_socket_dup(conn->sock);
780           silc_client_command_pending(conn, SILC_COMMAND_NONE,
781                                       server->resolve_cmd_ident,
782                                       silc_client_notify_by_server_pending,
783                                       res);
784           goto out;
785         }
786
787         /* Save the pointer to the client_entry pointer */
788         client_entry = (SilcClientEntry)server;
789       } else {
790         /* Find Channel entry */
791         silc_free(channel_id);
792         channel_id = id;
793         client_entry = (SilcClientEntry)
794           silc_client_get_channel_by_id(client, conn, channel_id);
795         if (!client_entry) {
796           silc_client_channel_set_wait(client, conn, channel,
797                                        conn->cmd_ident + 1);
798           silc_client_notify_by_server_resolve(client, conn, packet,
799                                                SILC_ID_CHANNEL, channel_id);
800           goto out;
801         }
802       }
803
804       /* Get the mode */
805       tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
806       if (!tmp)
807         goto out;
808
809       SILC_GET32_MSB(mode, tmp);
810
811       /* If information is being resolved for this channel, wait for it */
812       if (channel->resolve_cmd_ident) {
813         silc_client_channel_wait(client, conn, channel, packet);
814         goto out;
815       }
816
817       /* Save the new mode */
818       channel->mode = mode;
819
820       /* Get the cipher */
821       cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
822
823       /* Get the hmac */
824       hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
825       if (hmac) {
826         unsigned char hash[SILC_HASH_MAXLEN];
827
828         if (channel->hmac)
829           silc_hmac_free(channel->hmac);
830         if (!silc_hmac_alloc(hmac, NULL, &channel->hmac))
831           goto out;
832
833         silc_hash_make(silc_hmac_get_hash(channel->hmac),
834                        channel->key, channel->key_len / 8,
835                        hash);
836         silc_hmac_set_key(channel->hmac, hash,
837                           silc_hash_len(silc_hmac_get_hash(channel->hmac)));
838         memset(hash, 0, sizeof(hash));
839       }
840
841       /* Get the passphrase if it was set */
842       passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
843
844       /* Get the channel founder key if it was set */
845       tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
846       if (tmp) {
847         if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len, &founder_key))
848           founder_key = NULL;
849       }
850
851       /* Get user limit */
852       tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
853       if (tmp && tmp_len == 4)
854         SILC_GET32_MSB(channel->user_limit, tmp);
855       if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
856         channel->user_limit = 0;
857
858       /* Get the channel public key that was added or removed */
859       tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
860       if (tmp)
861         silc_buffer_set(&chpks, tmp, tmp_len);
862
863       /* Notify application. The channel entry is sent last as this notify
864          is for channel but application don't know it from the arguments
865          sent by server. */
866       client->internal->ops->notify(client, conn, type, id_type,
867                                     client_entry, mode, cipher, hmac,
868                                     passphrase, founder_key,
869                                     tmp ? &chpks : NULL, channel);
870
871       if (founder_key)
872         silc_pkcs_public_key_free(founder_key);
873     }
874     break;
875
876   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
877     /*
878      * Someone changed user's mode on a channel
879      */
880
881     SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
882
883     /* Get channel entry */
884     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
885                                 SILC_ID_CHANNEL);
886     if (!channel_id)
887       goto out;
888     channel = silc_client_get_channel_by_id(client, conn, channel_id);
889     if (!channel)
890       break;
891
892     /* Get ID */
893     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
894     if (!tmp)
895       goto out;
896     id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
897     if (!id)
898       goto out;
899
900     /* Find Client entry */
901     if (id_type == SILC_ID_CLIENT) {
902       /* Find Client entry */
903       client_id = id;
904       client_entry = silc_client_get_client_by_id(client, conn, client_id);
905       if (!client_entry) {
906         silc_client_channel_set_wait(client, conn, channel,
907                                      conn->cmd_ident + 1);
908         silc_client_notify_by_server_resolve(client, conn, packet,
909                                              SILC_ID_CLIENT, client_id);
910         goto out;
911       }
912
913       if (!client_entry->nickname) {
914         if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
915           /* Attach to existing resolving */
916           SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
917           res->packet = silc_packet_context_dup(packet);
918           res->context = client;
919           res->sock = silc_socket_dup(conn->sock);
920           silc_client_command_pending(conn, SILC_COMMAND_NONE,
921                                       client_entry->resolve_cmd_ident,
922                                       silc_client_notify_by_server_pending,
923                                       res);
924           goto out;
925         }
926
927         /* Do new resolving */
928         silc_client_channel_set_wait(client, conn, channel,
929                                      conn->cmd_ident + 1);
930         silc_client_notify_by_server_resolve(client, conn, packet,
931                                              SILC_ID_CLIENT, client_id);
932         client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
933         client_entry->resolve_cmd_ident = conn->cmd_ident;
934         goto out;
935       }
936     } else if (id_type == SILC_ID_SERVER) {
937       /* Find Server entry */
938       server_id = id;
939       server = silc_client_get_server_by_id(client, conn, server_id);
940       if (!server) {
941         silc_client_channel_set_wait(client, conn, channel,
942                                      conn->cmd_ident + 1);
943         silc_client_notify_by_server_resolve(client, conn, packet,
944                                              SILC_ID_SERVER, server_id);
945         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
946         if (!server)
947           goto out;
948
949         server->resolve_cmd_ident = conn->cmd_ident;
950         server_id = NULL;
951         goto out;
952       }
953
954       /* If entry being resoled, wait for it before processing this notify */
955       if (server->resolve_cmd_ident) {
956         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
957         res->packet = silc_packet_context_dup(packet);
958         res->context = client;
959         res->sock = silc_socket_dup(conn->sock);
960         silc_client_command_pending(conn, SILC_COMMAND_NONE,
961                                     server->resolve_cmd_ident,
962                                     silc_client_notify_by_server_pending, res);
963         goto out;
964       }
965
966       /* Save the pointer to the client_entry pointer */
967       client_entry = (SilcClientEntry)server;
968     } else {
969       /* Find Channel entry */
970       silc_free(channel_id);
971       channel_id = id;
972       client_entry = (SilcClientEntry)
973         silc_client_get_channel_by_id(client, conn, channel_id);
974       if (!client_entry) {
975         silc_client_channel_set_wait(client, conn, channel,
976                                      conn->cmd_ident + 1);
977         silc_client_notify_by_server_resolve(client, conn, packet,
978                                              SILC_ID_CHANNEL, channel_id);
979         goto out;
980       }
981     }
982
983     /* Get the mode */
984     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
985     if (!tmp)
986       goto out;
987
988     SILC_GET32_MSB(mode, tmp);
989
990     /* If information is being resolved for this channel, wait for it */
991     if (channel->resolve_cmd_ident) {
992       silc_client_channel_wait(client, conn, channel, packet);
993       goto out;
994     }
995
996     /* Get target Client ID */
997     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
998     if (!tmp)
999       goto out;
1000
1001     silc_free(client_id);
1002     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1003     if (!client_id)
1004       goto out;
1005
1006     /* Find target Client entry */
1007     client_entry2 =
1008       silc_client_get_client_by_id(client, conn, client_id);
1009     if (!client_entry2) {
1010       silc_client_notify_by_server_resolve(client, conn, packet,
1011                                            SILC_ID_CLIENT, client_id);
1012       goto out;
1013     }
1014
1015     /* Save the mode */
1016     chu = silc_client_on_channel(channel, client_entry2);
1017     if (chu)
1018       chu->mode = mode;
1019
1020     /* Notify application. The channel entry is sent last as this notify
1021        is for channel but application don't know it from the arguments
1022        sent by server. */
1023     client->internal->ops->notify(client, conn, type,
1024                                   id_type, client_entry, mode,
1025                                   client_entry2, channel);
1026     break;
1027
1028   case SILC_NOTIFY_TYPE_MOTD:
1029     /*
1030      * Received Message of the day
1031      */
1032
1033     SILC_LOG_DEBUG(("Notify: MOTD"));
1034
1035     /* Get motd */
1036     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1037     if (!tmp)
1038       goto out;
1039
1040     /* Notify application */
1041     client->internal->ops->notify(client, conn, type, tmp);
1042     break;
1043
1044   case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1045     /*
1046      * Router has enforced a new ID to a channel. Let's change the old
1047      * ID to the one provided here.
1048      */
1049
1050     SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1051
1052     /* Get the old ID */
1053     tmp = silc_argument_get_arg_type(args, 1, &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     /* Get the channel entry */
1061     channel = silc_client_get_channel_by_id(client, conn, channel_id);
1062     if (!channel)
1063       goto out;
1064
1065     silc_free(channel_id);
1066     channel_id = NULL;
1067
1068     /* Get the new ID */
1069     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1070     if (!tmp)
1071       goto out;
1072     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1073     if (!channel_id)
1074       goto out;
1075
1076     /* Replace the Channel ID */
1077     if (silc_client_replace_channel_id(client, conn, channel, channel_id))
1078       channel_id = NULL;
1079
1080     /* Notify application */
1081     client->internal->ops->notify(client, conn, type, channel, channel);
1082     break;
1083
1084   case SILC_NOTIFY_TYPE_KICKED:
1085     /*
1086      * A client (maybe me) was kicked from a channel
1087      */
1088
1089     SILC_LOG_DEBUG(("Notify: KICKED"));
1090
1091     /* Get Client ID */
1092     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1093     if (!tmp)
1094       goto out;
1095
1096     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1097     if (!client_id)
1098       goto out;
1099
1100     /* Find Client entry */
1101     client_entry = silc_client_get_client_by_id(client, conn, client_id);
1102     if (!client_entry)
1103       goto out;
1104
1105     /* Get channel entry */
1106     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1107                                 SILC_ID_CHANNEL);
1108     if (!channel_id)
1109       goto out;
1110     channel = silc_client_get_channel_by_id(client, conn, channel_id);
1111     if (!channel)
1112       break;
1113
1114     /* From protocol version 1.1 we get the kicker's client ID as well */
1115     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1116     if (tmp) {
1117       silc_free(client_id);
1118       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1119       if (!client_id)
1120         goto out;
1121
1122       /* Find kicker's client entry and if not found resolve it */
1123       client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
1124       if (!client_entry2) {
1125         silc_client_notify_by_server_resolve(client, conn, packet,
1126                                              SILC_ID_CLIENT, client_id);
1127         goto out;
1128       } else {
1129         if (client_entry2 != conn->local_entry)
1130           silc_client_nickname_format(client, conn, client_entry2);
1131       }
1132     }
1133
1134     /* Get comment */
1135     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1136
1137     /* Remove kicked client from channel */
1138     if (client_entry != conn->local_entry) {
1139       chu = silc_client_on_channel(channel, client_entry);
1140       if (chu) {
1141         silc_hash_table_del(client_entry->channels, channel);
1142         silc_hash_table_del(channel->user_list, client_entry);
1143         silc_free(chu);
1144       }
1145     }
1146
1147     /* Notify application. The channel entry is sent last as this notify
1148        is for channel but application don't know it from the arguments
1149        sent by server. */
1150     client->internal->ops->notify(client, conn, type, client_entry, tmp,
1151                                   client_entry2, channel);
1152
1153     /* Remove kicked client (us) from channel */
1154     if (client_entry == conn->local_entry) {
1155       /* If I was kicked from channel, remove the channel */
1156       if (conn->current_channel == channel)
1157         conn->current_channel = NULL;
1158       silc_client_del_channel(client, conn, channel);
1159     } else {
1160       if (!silc_hash_table_count(client_entry->channels)) {
1161         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1162         res->context = client;
1163         res->sock = silc_socket_dup(conn->sock);
1164         res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1165         silc_schedule_task_add(client->schedule, conn->sock->sock,
1166                                silc_client_notify_check_client, res,
1167                                (5 + (silc_rng_get_rn16(client->rng) % 529)),
1168                                0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1169       }
1170     }
1171     break;
1172
1173   case SILC_NOTIFY_TYPE_KILLED:
1174     {
1175       /*
1176        * A client (maybe me) was killed from the network.
1177        */
1178       char *comment;
1179       SilcUInt32 comment_len;
1180
1181       SILC_LOG_DEBUG(("Notify: KILLED"));
1182
1183       /* Get Client ID */
1184       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1185       if (!tmp)
1186         goto out;
1187
1188       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1189       if (!client_id)
1190         goto out;
1191
1192       /* Find Client entry */
1193       client_entry = silc_client_get_client_by_id(client, conn, client_id);
1194       if (!client_entry)
1195         goto out;
1196
1197       /* Get comment */
1198       comment = silc_argument_get_arg_type(args, 2, &comment_len);
1199
1200       /* From protocol version 1.1 we get killer's client ID as well */
1201       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1202       if (tmp) {
1203         silc_free(client_id);
1204         client_id = NULL;
1205         id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1206         if (!id)
1207           goto out;
1208
1209         /* Find Client entry */
1210         if (id_type == SILC_ID_CLIENT) {
1211           /* Find Client entry */
1212           client_id = id;
1213           client_entry2 = silc_client_get_client_by_id(client, conn,
1214                                                        client_id);
1215           if (!client_entry) {
1216             silc_client_notify_by_server_resolve(client, conn, packet,
1217                                                  SILC_ID_CLIENT, client_id);
1218             goto out;
1219           }
1220         } else if (id_type == SILC_ID_SERVER) {
1221           /* Find Server entry */
1222           server_id = id;
1223           server = silc_client_get_server_by_id(client, conn, server_id);
1224           if (!server) {
1225             silc_client_notify_by_server_resolve(client, conn, packet,
1226                                                  SILC_ID_SERVER, server_id);
1227             server = silc_client_add_server(client, conn, NULL, NULL,
1228                                             server_id);
1229             if (!server)
1230               goto out;
1231
1232             server->resolve_cmd_ident = conn->cmd_ident;
1233             server_id = NULL;
1234             goto out;
1235           }
1236
1237           if (server->resolve_cmd_ident) {
1238             SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1239             res->packet = silc_packet_context_dup(packet);
1240             res->context = client;
1241             res->sock = silc_socket_dup(conn->sock);
1242             silc_client_command_pending(conn, SILC_COMMAND_NONE,
1243                                         server->resolve_cmd_ident,
1244                                         silc_client_notify_by_server_pending,
1245                                         res);
1246             goto out;
1247           }
1248
1249           /* Save the pointer to the client_entry pointer */
1250           client_entry2 = (SilcClientEntry)server;
1251         } else {
1252           /* Find Channel entry */
1253           channel_id = id;
1254           channel = silc_client_get_channel_by_id(client, conn, channel_id);
1255           if (!channel) {
1256             silc_client_notify_by_server_resolve(client, conn, packet,
1257                                                  SILC_ID_CHANNEL, channel_id);
1258             goto out;
1259           }
1260
1261           /* Save the pointer to the client_entry pointer */
1262           client_entry2 = (SilcClientEntry)channel;
1263           silc_free(channel_id);
1264           channel_id = NULL;
1265         }
1266       }
1267
1268       /* Notify application. */
1269       client->internal->ops->notify(client, conn, type, client_entry,
1270                                     comment, id_type, client_entry2);
1271
1272       if (client_entry != conn->local_entry)
1273         /* Remove the client from all channels and free it */
1274         silc_client_del_client(client, conn, client_entry);
1275     }
1276     break;
1277
1278   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1279     {
1280       /*
1281        * A server quit the SILC network and some clients must be removed
1282        * from channels as they quit as well.
1283        */
1284       SilcClientEntry *clients = NULL;
1285       SilcUInt32 clients_count = 0;
1286       int i;
1287
1288       SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1289
1290       for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1291         /* Get Client ID */
1292         tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1293         if (tmp) {
1294           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1295           if (!client_id)
1296             goto out;
1297
1298           /* Get the client entry */
1299           client_entry = silc_client_get_client_by_id(client, conn, client_id);
1300           if (client_entry) {
1301             clients = silc_realloc(clients, sizeof(*clients) *
1302                                    (clients_count + 1));
1303             clients[clients_count] = client_entry;
1304             clients_count++;
1305           }
1306           silc_free(client_id);
1307         }
1308       }
1309       client_id = NULL;
1310
1311       /* Notify application. We don't keep server entries so the server
1312          entry is returned as NULL. The client's are returned as array
1313          of SilcClientEntry pointers. */
1314       client->internal->ops->notify(client, conn, type, NULL,
1315                                     clients, clients_count);
1316
1317       for (i = 0; i < clients_count; i++) {
1318         /* Remove client from all channels */
1319         client_entry = clients[i];
1320         if (client_entry == conn->local_entry)
1321           continue;
1322
1323         /* Remove the client from all channels and free it */
1324         silc_client_del_client(client, conn, client_entry);
1325       }
1326       silc_free(clients);
1327
1328     }
1329     break;
1330
1331   case SILC_NOTIFY_TYPE_ERROR:
1332     {
1333       /*
1334        * Some has occurred and server is notifying us about it.
1335        */
1336       SilcStatus error;
1337
1338       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1339       if (!tmp && tmp_len != 1)
1340         goto out;
1341       error = (SilcStatus)tmp[0];
1342
1343       SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1344
1345       if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1346         tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1347         if (tmp) {
1348           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1349           if (!client_id)
1350             goto out;
1351           client_entry = silc_client_get_client_by_id(client, conn,
1352                                                       client_id);
1353           if (client_entry)
1354             silc_client_del_client(client, conn, client_entry);
1355         }
1356       }
1357
1358       /* Notify application. */
1359       client->internal->ops->notify(client, conn, type, error);
1360     }
1361     break;
1362
1363   case SILC_NOTIFY_TYPE_WATCH:
1364     {
1365       /*
1366        * Received notify about some client we are watching
1367        */
1368       SilcNotifyType notify = 0;
1369       SilcBool del_client = FALSE;
1370       unsigned char *pk;
1371       SilcUInt32 pk_len;
1372       SilcPublicKey public_key = NULL;
1373
1374       SILC_LOG_DEBUG(("Notify: WATCH"));
1375
1376       /* Get sender Client ID */
1377       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1378       if (!tmp)
1379         goto out;
1380       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1381       if (!client_id)
1382         goto out;
1383
1384       /* Find Client entry and if not found query it */
1385       client_entry = silc_client_get_client_by_id(client, conn, client_id);
1386       if (!client_entry) {
1387         silc_client_notify_by_server_resolve(client, conn, packet,
1388                                              SILC_ID_CLIENT, client_id);
1389         goto out;
1390       }
1391
1392       /* Get user mode */
1393       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1394       if (!tmp || tmp_len != 4)
1395         goto out;
1396       SILC_GET32_MSB(mode, tmp);
1397
1398       /* Get notify type */
1399       tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1400       if (tmp && tmp_len != 2)
1401         goto out;
1402       if (tmp)
1403         SILC_GET16_MSB(notify, tmp);
1404
1405       /* Get nickname */
1406       tmp = silc_argument_get_arg_type(args, 2, NULL);
1407       if (tmp) {
1408         char *tmp_nick = NULL;
1409
1410         if (client->internal->params->nickname_parse)
1411           client->internal->params->nickname_parse(client_entry->nickname,
1412                                                    &tmp_nick);
1413         else
1414           tmp_nick = strdup(tmp);
1415
1416         /* If same nick, the client was new to us and has become "present"
1417            to network.  Send NULL as nick to application. */
1418         if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1419           tmp = NULL;
1420
1421         silc_free(tmp_nick);
1422       }
1423
1424       /* Get public key, if present */
1425       pk = silc_argument_get_arg_type(args, 5, &pk_len);
1426       if (pk && !client_entry->public_key) {
1427         if (silc_pkcs_public_key_payload_decode(pk, pk_len, &public_key)) {
1428           client_entry->public_key = public_key;
1429           public_key = NULL;
1430         }
1431       }
1432
1433       /* Notify application. */
1434       client->internal->ops->notify(client, conn, type, client_entry,
1435                                     tmp, mode, notify,
1436                                     client_entry->public_key);
1437
1438       client_entry->mode = mode;
1439
1440       /* If nickname was changed, remove the client entry unless the
1441          client is on some channel */
1442       if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1443           !silc_hash_table_count(client_entry->channels))
1444         del_client = TRUE;
1445       else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1446                notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1447                notify == SILC_NOTIFY_TYPE_KILLED)
1448         del_client = TRUE;
1449
1450       if (del_client) {
1451         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1452         res->context = client;
1453         res->sock = silc_socket_dup(conn->sock);
1454         res->packet = client_id;
1455         client_id = NULL;
1456         silc_schedule_task_add(client->schedule, conn->sock->sock,
1457                                silc_client_notify_del_client_cb, res,
1458                                1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1459       }
1460
1461       silc_pkcs_public_key_free(public_key);
1462     }
1463     break;
1464
1465   default:
1466     break;
1467   }
1468
1469  out:
1470   silc_notify_payload_free(payload);
1471   silc_free(client_id);
1472   silc_free(channel_id);
1473   silc_free(server_id);
1474 }