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