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