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