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