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