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