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