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