Added topic to SilcChannelEntry.
[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 - 2004 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         !strcmp(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 the channel public key that was added or removed */
848       tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
849       if (tmp)
850         silc_buffer_set(&chpks, tmp, tmp_len);
851
852       /* Notify application. The channel entry is sent last as this notify
853          is for channel but application don't know it from the arguments
854          sent by server. */
855       client->internal->ops->notify(client, conn, type, id_type,
856                                     client_entry, mode, cipher, hmac,
857                                     passphrase, founder_key,
858                                     tmp ? &chpks : NULL, channel);
859
860       if (founder_key)
861         silc_pkcs_public_key_free(founder_key);
862     }
863     break;
864
865   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
866     /*
867      * Someone changed user's mode on a channel
868      */
869
870     SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
871
872     /* Get channel entry */
873     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
874                                 SILC_ID_CHANNEL);
875     if (!channel_id)
876       goto out;
877     channel = silc_client_get_channel_by_id(client, conn, channel_id);
878     if (!channel)
879       break;
880
881     /* Get ID */
882     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
883     if (!tmp)
884       goto out;
885     id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
886     if (!id)
887       goto out;
888
889     /* Find Client entry */
890     if (id_type == SILC_ID_CLIENT) {
891       /* Find Client entry */
892       client_id = id;
893       client_entry = silc_client_get_client_by_id(client, conn, client_id);
894       if (!client_entry) {
895         silc_client_channel_set_wait(client, conn, channel,
896                                      conn->cmd_ident + 1);
897         silc_client_notify_by_server_resolve(client, conn, packet,
898                                              SILC_ID_CLIENT, client_id);
899         goto out;
900       }
901
902       if (!client_entry->nickname) {
903         if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
904           /* Attach to existing resolving */
905           SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
906           res->packet = silc_packet_context_dup(packet);
907           res->context = client;
908           res->sock = silc_socket_dup(conn->sock);
909           silc_client_command_pending(conn, SILC_COMMAND_NONE,
910                                       client_entry->resolve_cmd_ident,
911                                       silc_client_notify_by_server_pending,
912                                       res);
913           goto out;
914         }
915
916         /* Do new resolving */
917         silc_client_channel_set_wait(client, conn, channel,
918                                      conn->cmd_ident + 1);
919         silc_client_notify_by_server_resolve(client, conn, packet,
920                                              SILC_ID_CLIENT, client_id);
921         client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
922         client_entry->resolve_cmd_ident = conn->cmd_ident;
923         goto out;
924       }
925     } else if (id_type == SILC_ID_SERVER) {
926       /* Find Server entry */
927       server_id = id;
928       server = silc_client_get_server_by_id(client, conn, server_id);
929       if (!server) {
930         silc_client_channel_set_wait(client, conn, channel,
931                                      conn->cmd_ident + 1);
932         silc_client_notify_by_server_resolve(client, conn, packet,
933                                              SILC_ID_SERVER, server_id);
934         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
935         if (!server)
936           goto out;
937
938         server->resolve_cmd_ident = conn->cmd_ident;
939         server_id = NULL;
940         goto out;
941       }
942
943       /* If entry being resoled, wait for it before processing this notify */
944       if (server->resolve_cmd_ident) {
945         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
946         res->packet = silc_packet_context_dup(packet);
947         res->context = client;
948         res->sock = silc_socket_dup(conn->sock);
949         silc_client_command_pending(conn, SILC_COMMAND_NONE,
950                                     server->resolve_cmd_ident,
951                                     silc_client_notify_by_server_pending, res);
952         goto out;
953       }
954
955       /* Save the pointer to the client_entry pointer */
956       client_entry = (SilcClientEntry)server;
957     } else {
958       /* Find Channel entry */
959       silc_free(channel_id);
960       channel_id = id;
961       client_entry = (SilcClientEntry)
962         silc_client_get_channel_by_id(client, conn, channel_id);
963       if (!client_entry) {
964         silc_client_channel_set_wait(client, conn, channel,
965                                      conn->cmd_ident + 1);
966         silc_client_notify_by_server_resolve(client, conn, packet,
967                                              SILC_ID_CHANNEL, channel_id);
968         goto out;
969       }
970     }
971
972     /* Get the mode */
973     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
974     if (!tmp)
975       goto out;
976
977     SILC_GET32_MSB(mode, tmp);
978
979     /* If information is being resolved for this channel, wait for it */
980     if (channel->resolve_cmd_ident) {
981       silc_client_channel_wait(client, conn, channel, packet);
982       goto out;
983     }
984
985     /* Get target Client ID */
986     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
987     if (!tmp)
988       goto out;
989
990     silc_free(client_id);
991     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
992     if (!client_id)
993       goto out;
994
995     /* Find target Client entry */
996     client_entry2 =
997       silc_client_get_client_by_id(client, conn, client_id);
998     if (!client_entry2) {
999       silc_client_notify_by_server_resolve(client, conn, packet,
1000                                            SILC_ID_CLIENT, client_id);
1001       goto out;
1002     }
1003
1004     /* Save the mode */
1005     chu = silc_client_on_channel(channel, client_entry2);
1006     if (chu)
1007       chu->mode = mode;
1008
1009     /* Notify application. The channel entry is sent last as this notify
1010        is for channel but application don't know it from the arguments
1011        sent by server. */
1012     client->internal->ops->notify(client, conn, type,
1013                                   id_type, client_entry, mode,
1014                                   client_entry2, channel);
1015     break;
1016
1017   case SILC_NOTIFY_TYPE_MOTD:
1018     /*
1019      * Received Message of the day
1020      */
1021
1022     SILC_LOG_DEBUG(("Notify: MOTD"));
1023
1024     /* Get motd */
1025     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1026     if (!tmp)
1027       goto out;
1028
1029     /* Notify application */
1030     client->internal->ops->notify(client, conn, type, tmp);
1031     break;
1032
1033   case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1034     /*
1035      * Router has enforced a new ID to a channel. Let's change the old
1036      * ID to the one provided here.
1037      */
1038
1039     SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1040
1041     /* Get the old ID */
1042     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1043     if (!tmp)
1044       goto out;
1045     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1046     if (!channel_id)
1047       goto out;
1048
1049     /* Get the channel entry */
1050     channel = silc_client_get_channel_by_id(client, conn, channel_id);
1051     if (!channel)
1052       goto out;
1053
1054     silc_free(channel_id);
1055     channel_id = NULL;
1056
1057     /* Get the new ID */
1058     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1059     if (!tmp)
1060       goto out;
1061     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1062     if (!channel_id)
1063       goto out;
1064
1065     /* Replace the Channel ID */
1066     if (silc_client_replace_channel_id(client, conn, channel, channel_id))
1067       channel_id = NULL;
1068
1069     /* Notify application */
1070     client->internal->ops->notify(client, conn, type, channel, channel);
1071     break;
1072
1073   case SILC_NOTIFY_TYPE_KICKED:
1074     /*
1075      * A client (maybe me) was kicked from a channel
1076      */
1077
1078     SILC_LOG_DEBUG(("Notify: KICKED"));
1079
1080     /* Get Client ID */
1081     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1082     if (!tmp)
1083       goto out;
1084
1085     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1086     if (!client_id)
1087       goto out;
1088
1089     /* Find Client entry */
1090     client_entry = silc_client_get_client_by_id(client, conn, client_id);
1091     if (!client_entry)
1092       goto out;
1093
1094     /* Get channel entry */
1095     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1096                                 SILC_ID_CHANNEL);
1097     if (!channel_id)
1098       goto out;
1099     channel = silc_client_get_channel_by_id(client, conn, channel_id);
1100     if (!channel)
1101       break;
1102
1103     /* From protocol version 1.1 we get the kicker's client ID as well */
1104     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1105     if (tmp) {
1106       silc_free(client_id);
1107       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1108       if (!client_id)
1109         goto out;
1110
1111       /* Find kicker's client entry and if not found resolve it */
1112       client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
1113       if (!client_entry2) {
1114         silc_client_notify_by_server_resolve(client, conn, packet,
1115                                              SILC_ID_CLIENT, client_id);
1116         goto out;
1117       } else {
1118         if (client_entry2 != conn->local_entry)
1119           silc_client_nickname_format(client, conn, client_entry2);
1120       }
1121     }
1122
1123     /* Get comment */
1124     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1125
1126     /* Remove kicked client from channel */
1127     if (client_entry != conn->local_entry) {
1128       chu = silc_client_on_channel(channel, client_entry);
1129       if (chu) {
1130         silc_hash_table_del(client_entry->channels, channel);
1131         silc_hash_table_del(channel->user_list, client_entry);
1132         silc_free(chu);
1133       }
1134     }
1135
1136     /* Notify application. The channel entry is sent last as this notify
1137        is for channel but application don't know it from the arguments
1138        sent by server. */
1139     client->internal->ops->notify(client, conn, type, client_entry, tmp,
1140                                   client_entry2, channel);
1141
1142     /* Remove kicked client (us) from channel */
1143     if (client_entry == conn->local_entry) {
1144       /* If I was kicked from channel, remove the channel */
1145       if (conn->current_channel == channel)
1146         conn->current_channel = NULL;
1147       silc_client_del_channel(client, conn, channel);
1148     } else {
1149       if (!silc_hash_table_count(client_entry->channels)) {
1150         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1151         res->context = client;
1152         res->sock = silc_socket_dup(conn->sock);
1153         res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1154         silc_schedule_task_add(client->schedule, conn->sock->sock,
1155                                silc_client_notify_check_client, res,
1156                                (5 + (silc_rng_get_rn16(client->rng) % 529)),
1157                                0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1158       }
1159     }
1160     break;
1161
1162   case SILC_NOTIFY_TYPE_KILLED:
1163     {
1164       /*
1165        * A client (maybe me) was killed from the network.
1166        */
1167       char *comment;
1168       SilcUInt32 comment_len;
1169
1170       SILC_LOG_DEBUG(("Notify: KILLED"));
1171
1172       /* Get Client ID */
1173       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1174       if (!tmp)
1175         goto out;
1176
1177       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1178       if (!client_id)
1179         goto out;
1180
1181       /* Find Client entry */
1182       client_entry = silc_client_get_client_by_id(client, conn, client_id);
1183       if (!client_entry)
1184         goto out;
1185
1186       /* Get comment */
1187       comment = silc_argument_get_arg_type(args, 2, &comment_len);
1188
1189       /* From protocol version 1.1 we get killer's client ID as well */
1190       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1191       if (tmp) {
1192         silc_free(client_id);
1193         client_id = NULL;
1194         id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1195         if (!id)
1196           goto out;
1197
1198         /* Find Client entry */
1199         if (id_type == SILC_ID_CLIENT) {
1200           /* Find Client entry */
1201           client_id = id;
1202           client_entry2 = silc_client_get_client_by_id(client, conn,
1203                                                        client_id);
1204           if (!client_entry) {
1205             silc_client_notify_by_server_resolve(client, conn, packet,
1206                                                  SILC_ID_CLIENT, client_id);
1207             goto out;
1208           }
1209         } else if (id_type == SILC_ID_SERVER) {
1210           /* Find Server entry */
1211           server_id = id;
1212           server = silc_client_get_server_by_id(client, conn, server_id);
1213           if (!server) {
1214             silc_client_notify_by_server_resolve(client, conn, packet,
1215                                                  SILC_ID_SERVER, server_id);
1216             server = silc_client_add_server(client, conn, NULL, NULL,
1217                                             server_id);
1218             if (!server)
1219               goto out;
1220
1221             server->resolve_cmd_ident = conn->cmd_ident;
1222             server_id = NULL;
1223             goto out;
1224           }
1225
1226           if (server->resolve_cmd_ident) {
1227             SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1228             res->packet = silc_packet_context_dup(packet);
1229             res->context = client;
1230             res->sock = silc_socket_dup(conn->sock);
1231             silc_client_command_pending(conn, SILC_COMMAND_NONE,
1232                                         server->resolve_cmd_ident,
1233                                         silc_client_notify_by_server_pending,
1234                                         res);
1235             goto out;
1236           }
1237
1238           /* Save the pointer to the client_entry pointer */
1239           client_entry2 = (SilcClientEntry)server;
1240         } else {
1241           /* Find Channel entry */
1242           channel_id = id;
1243           channel = silc_client_get_channel_by_id(client, conn, channel_id);
1244           if (!channel) {
1245             silc_client_notify_by_server_resolve(client, conn, packet,
1246                                                  SILC_ID_CHANNEL, channel_id);
1247             goto out;
1248           }
1249
1250           /* Save the pointer to the client_entry pointer */
1251           client_entry2 = (SilcClientEntry)channel;
1252           silc_free(channel_id);
1253           channel_id = NULL;
1254         }
1255       }
1256
1257       /* Notify application. */
1258       client->internal->ops->notify(client, conn, type, client_entry,
1259                                     comment, id_type, client_entry2);
1260
1261       if (client_entry != conn->local_entry)
1262         /* Remove the client from all channels and free it */
1263         silc_client_del_client(client, conn, client_entry);
1264     }
1265     break;
1266
1267   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1268     {
1269       /*
1270        * A server quit the SILC network and some clients must be removed
1271        * from channels as they quit as well.
1272        */
1273       SilcClientEntry *clients = NULL;
1274       SilcUInt32 clients_count = 0;
1275       int i;
1276
1277       SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1278
1279       for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1280         /* Get Client ID */
1281         tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1282         if (tmp) {
1283           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1284           if (!client_id)
1285             goto out;
1286
1287           /* Get the client entry */
1288           client_entry = silc_client_get_client_by_id(client, conn, client_id);
1289           if (client_entry) {
1290             clients = silc_realloc(clients, sizeof(*clients) *
1291                                    (clients_count + 1));
1292             clients[clients_count] = client_entry;
1293             clients_count++;
1294           }
1295           silc_free(client_id);
1296         }
1297       }
1298       client_id = NULL;
1299
1300       /* Notify application. We don't keep server entries so the server
1301          entry is returned as NULL. The client's are returned as array
1302          of SilcClientEntry pointers. */
1303       client->internal->ops->notify(client, conn, type, NULL,
1304                                     clients, clients_count);
1305
1306       for (i = 0; i < clients_count; i++) {
1307         /* Remove client from all channels */
1308         client_entry = clients[i];
1309         if (client_entry == conn->local_entry)
1310           continue;
1311
1312         /* Remove the client from all channels and free it */
1313         silc_client_del_client(client, conn, client_entry);
1314       }
1315       silc_free(clients);
1316
1317     }
1318     break;
1319
1320   case SILC_NOTIFY_TYPE_ERROR:
1321     {
1322       /*
1323        * Some has occurred and server is notifying us about it.
1324        */
1325       SilcStatus error;
1326
1327       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1328       if (!tmp && tmp_len != 1)
1329         goto out;
1330       error = (SilcStatus)tmp[0];
1331
1332       SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1333
1334       if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1335         tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1336         if (tmp) {
1337           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1338           if (!client_id)
1339             goto out;
1340           client_entry = silc_client_get_client_by_id(client, conn,
1341                                                       client_id);
1342           if (client_entry)
1343             silc_client_del_client(client, conn, client_entry);
1344         }
1345       }
1346
1347       /* Notify application. */
1348       client->internal->ops->notify(client, conn, type, error);
1349     }
1350     break;
1351
1352   case SILC_NOTIFY_TYPE_WATCH:
1353     {
1354       /*
1355        * Received notify about some client we are watching
1356        */
1357       SilcNotifyType notify = 0;
1358       bool del_client = FALSE;
1359
1360       SILC_LOG_DEBUG(("Notify: WATCH"));
1361
1362       /* Get sender Client ID */
1363       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1364       if (!tmp)
1365         goto out;
1366       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1367       if (!client_id)
1368         goto out;
1369
1370       /* Find Client entry and if not found query it */
1371       client_entry = silc_client_get_client_by_id(client, conn, client_id);
1372       if (!client_entry) {
1373         silc_client_notify_by_server_resolve(client, conn, packet,
1374                                              SILC_ID_CLIENT, client_id);
1375         goto out;
1376       }
1377
1378       /* Get user mode */
1379       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1380       if (!tmp || tmp_len != 4)
1381         goto out;
1382       SILC_GET32_MSB(mode, tmp);
1383
1384       /* Get notify type */
1385       tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1386       if (tmp && tmp_len != 2)
1387         goto out;
1388       if (tmp)
1389         SILC_GET16_MSB(notify, tmp);
1390
1391       /* Get nickname */
1392       tmp = silc_argument_get_arg_type(args, 2, NULL);
1393       if (tmp) {
1394         char *tmp_nick = NULL;
1395
1396         if (client->internal->params->nickname_parse)
1397           client->internal->params->nickname_parse(client_entry->nickname,
1398                                                    &tmp_nick);
1399         else
1400           tmp_nick = strdup(tmp);
1401
1402         /* If same nick, the client was new to us and has become "present"
1403            to network.  Send NULL as nick to application. */
1404         if (tmp_nick && !strcmp(tmp, tmp_nick))
1405           tmp = NULL;
1406
1407         silc_free(tmp_nick);
1408       }
1409
1410       /* Notify application. */
1411       client->internal->ops->notify(client, conn, type, client_entry,
1412                                     tmp, mode, notify);
1413
1414       client_entry->mode = mode;
1415
1416       /* If nickname was changed, remove the client entry unless the
1417          client is on some channel */
1418       if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1419           !silc_hash_table_count(client_entry->channels))
1420         del_client = TRUE;
1421       else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1422                notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1423                notify == SILC_NOTIFY_TYPE_KILLED)
1424         del_client = TRUE;
1425
1426       if (del_client) {
1427         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1428         res->context = client;
1429         res->sock = silc_socket_dup(conn->sock);
1430         res->packet = client_id;
1431         client_id = NULL;
1432         silc_schedule_task_add(client->schedule, conn->sock->sock,
1433                                silc_client_notify_del_client_cb, res,
1434                                1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1435       }
1436     }
1437     break;
1438
1439   default:
1440     break;
1441   }
1442
1443  out:
1444   silc_notify_payload_free(payload);
1445   silc_free(client_id);
1446   silc_free(channel_id);
1447   silc_free(server_id);
1448 }