Fixed channel MAC key setting in JOIN notify and command reply
[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_hmac_set_key(newhmac, tmp, tmp_len);
922       if (channel->internal.hmac)
923         silc_hmac_free(channel->internal.hmac);
924       channel->internal.hmac = newhmac;
925       memset(hash, 0, sizeof(hash));
926     }
927   }
928
929   /* Get the passphrase if it was set */
930   passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
931
932   /* Get user limit */
933   tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
934   if (tmp && tmp_len == 4)
935     SILC_GET32_MSB(channel->user_limit, tmp);
936   if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
937     channel->user_limit = 0;
938
939   /* Get the channel public key that was added or removed */
940   tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
941   if (tmp)
942     silc_client_channel_save_public_keys(channel, tmp, tmp_len, FALSE);
943   else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
944     silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
945
946   /* Save the new mode */
947   channel->mode = mode;
948
949   silc_rwlock_unlock(channel->internal.lock);
950
951   /* Notify application. */
952   NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
953          passphrase, channel->founder_key, chpks, channel);
954
955  out:
956   if (founder_key)
957     silc_pkcs_public_key_free(founder_key);
958   if (chpks)
959     silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
960   if (client_entry)
961     silc_client_unref_client(client, conn, client_entry);
962   if (server)
963     silc_client_unref_server(client, conn, server);
964   if (channel_entry)
965     silc_client_unref_channel(client, conn, channel_entry);
966   silc_client_unref_channel(client, conn, channel);
967
968   /** Notify processed */
969   silc_fsm_next(fsm, silc_client_notify_processed);
970   return SILC_FSM_CONTINUE;
971 }
972
973 /***************************** CUMODE_CHANGE ********************************/
974
975 /* Someone changed a user's mode on a channel */
976
977 SILC_FSM_STATE(silc_client_notify_cumode_change)
978 {
979   SilcClientConnection conn = fsm_context;
980   SilcClient client = conn->client;
981   SilcClientNotify notify = state_context;
982   SilcNotifyPayload payload = notify->payload;
983   SilcPacket packet = notify->packet;
984   SilcNotifyType type = silc_notify_get_type(payload);
985   SilcArgumentPayload args = silc_notify_get_args(payload);
986   SilcClientEntry client_entry = NULL, client_entry2 = NULL;
987   SilcChannelEntry channel = NULL, channel_entry = NULL;
988   SilcServerEntry server = NULL;
989   SilcChannelUser chu;
990   void *entry;
991   unsigned char *tmp;
992   SilcUInt32 tmp_len, mode;
993   SilcID id, id2;
994
995   SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
996
997   /* Get channel entry */
998   if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
999                       &id.u.channel_id, sizeof(id.u.channel_id)))
1000     goto out;
1001   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1002   if (!channel)
1003     goto out;
1004
1005   /* If channel is being resolved handle notify after resolving */
1006   if (channel->internal.resolve_cmd_ident) {
1007     silc_client_unref_channel(client, conn, channel);
1008     SILC_FSM_CALL(silc_client_command_pending(
1009                                       conn, SILC_COMMAND_NONE,
1010                                       channel->internal.resolve_cmd_ident,
1011                                       silc_client_notify_wait_continue,
1012                                       notify));
1013     /* NOT REACHED */
1014   }
1015
1016   /* Get target Client ID */
1017   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
1018     goto out;
1019
1020   /* Find target Client entry */
1021   client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
1022   if (!client_entry2 || !client_entry2->internal.valid) {
1023     /** Resolve client */
1024     silc_client_unref_client(client, conn, client_entry2);
1025     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1026                                          client, conn, &id2.u.client_id, NULL,
1027                                          silc_client_notify_resolved,
1028                                          notify));
1029     /* NOT REACHED */
1030   }
1031
1032   /* If target client is not on channel, ignore this notify */
1033   if (!silc_client_on_channel(channel, client_entry2))
1034     goto out;
1035
1036   /* Get the mode */
1037   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1038   if (!tmp)
1039     goto out;
1040   SILC_GET32_MSB(mode, tmp);
1041
1042   /* Get ID of mode changer */
1043   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1044     goto out;
1045
1046   if (id.type == SILC_ID_CLIENT) {
1047     /* Find Client entry */
1048     client_entry = notify->client_entry;
1049     if (!client_entry) {
1050       client_entry = silc_client_get_client(client, conn, &id.u.client_id);
1051       if (!client_entry || !client_entry->internal.valid) {
1052         /** Resolve client */
1053         notify->channel = channel;
1054         notify->client_entry = client_entry;
1055         SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1056                       silc_client_get_client_by_id_resolve(
1057                                            client, conn, &id.u.client_id, NULL,
1058                                            silc_client_notify_resolved,
1059                                            notify));
1060         /* NOT REACHED */
1061       }
1062     }
1063
1064     /* If client is not on channel, ignore this notify */
1065     if (!silc_client_on_channel(channel, client_entry))
1066       goto out;
1067
1068     entry = client_entry;
1069   } else if (id.type == SILC_ID_SERVER) {
1070     /* Find Server entry */
1071     server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1072     if (!server) {
1073       /** Resolve server */
1074       notify->channel = channel;
1075       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1076                     silc_client_get_server_by_id_resolve(
1077                                            client, conn, &id.u.server_id,
1078                                            silc_client_notify_resolved,
1079                                            notify));
1080       /* NOT REACHED */
1081     }
1082     entry = server;
1083   } else {
1084     /* Find Channel entry */
1085     channel_entry = silc_client_get_channel_by_id(client, conn,
1086                                                   &id.u.channel_id);
1087     if (!channel_entry) {
1088       /** Resolve channel */
1089       notify->channel = channel;
1090       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1091                     silc_client_get_channel_by_id_resolve(
1092                                     client, conn, &id.u.channel_id,
1093                                     silc_client_notify_resolved,
1094                                     notify));
1095       /* NOT REACHED */
1096     }
1097     entry = channel_entry;
1098   }
1099
1100   /* Save the mode */
1101   silc_rwlock_wrlock(channel->internal.lock);
1102   chu = silc_client_on_channel(channel, client_entry2);
1103   if (chu)
1104     chu->mode = mode;
1105   silc_rwlock_unlock(channel->internal.lock);
1106
1107   /* Notify application. */
1108   NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1109
1110  out:
1111   silc_client_unref_client(client, conn, client_entry2);
1112   if (client_entry)
1113     silc_client_unref_client(client, conn, client_entry);
1114   if (server)
1115     silc_client_unref_server(client, conn, server);
1116   if (channel_entry)
1117     silc_client_unref_channel(client, conn, channel_entry);
1118   silc_client_unref_channel(client, conn, channel);
1119
1120   /** Notify processed */
1121   silc_fsm_next(fsm, silc_client_notify_processed);
1122   return SILC_FSM_CONTINUE;
1123 }
1124
1125 /********************************* MOTD *************************************/
1126
1127 /* Received Message of the day */
1128
1129 SILC_FSM_STATE(silc_client_notify_motd)
1130 {
1131   SilcClientConnection conn = fsm_context;
1132   SilcClient client = conn->client;
1133   SilcClientNotify notify = state_context;
1134   SilcNotifyPayload payload = notify->payload;
1135   SilcNotifyType type = silc_notify_get_type(payload);
1136   SilcArgumentPayload args = silc_notify_get_args(payload);
1137   unsigned char *tmp;
1138   SilcUInt32 tmp_len;
1139
1140   SILC_LOG_DEBUG(("Notify: MOTD"));
1141
1142   /* Get motd */
1143   tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1144   if (!tmp)
1145     goto out;
1146
1147   /* Notify application */
1148   NOTIFY(client, conn, type, tmp);
1149
1150  out:
1151   /** Notify processed */
1152   silc_fsm_next(fsm, silc_client_notify_processed);
1153   return SILC_FSM_CONTINUE;
1154 }
1155
1156 /**************************** CHANNEL CHANGE ********************************/
1157
1158 /* Router has enforced a new ID to a channel, change it */
1159
1160 SILC_FSM_STATE(silc_client_notify_channel_change)
1161 {
1162   SilcClientConnection conn = fsm_context;
1163   SilcClient client = conn->client;
1164   SilcClientNotify notify = state_context;
1165   SilcNotifyPayload payload = notify->payload;
1166   SilcNotifyType type = silc_notify_get_type(payload);
1167   SilcArgumentPayload args = silc_notify_get_args(payload);
1168   SilcChannelEntry channel = NULL;
1169   SilcID id;
1170
1171   SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1172
1173   /* Get the old ID */
1174   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1175     goto out;
1176
1177   /* Get the channel entry */
1178   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1179   if (!channel)
1180     goto out;
1181
1182   /* If channel is being resolved handle notify after resolving */
1183   if (channel->internal.resolve_cmd_ident) {
1184     silc_client_unref_channel(client, conn, channel);
1185     SILC_FSM_CALL(silc_client_command_pending(
1186                                       conn, SILC_COMMAND_NONE,
1187                                       channel->internal.resolve_cmd_ident,
1188                                       silc_client_notify_wait_continue,
1189                                       notify));
1190     /* NOT REACHED */
1191   }
1192
1193   /* Get the new ID */
1194   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1195     goto out;
1196
1197   /* Replace the Channel ID */
1198   if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1199     goto out;
1200
1201   /* Notify application */
1202   NOTIFY(client, conn, type, channel, channel);
1203
1204  out:
1205   /** Notify processed */
1206   silc_client_unref_channel(client, conn, channel);
1207   silc_fsm_next(fsm, silc_client_notify_processed);
1208   return SILC_FSM_CONTINUE;
1209 }
1210
1211 /******************************** KICKED ************************************/
1212
1213 /* Some client was kicked from a channel */
1214
1215 SILC_FSM_STATE(silc_client_notify_kicked)
1216 {
1217   SilcClientConnection conn = fsm_context;
1218   SilcClient client = conn->client;
1219   SilcClientNotify notify = state_context;
1220   SilcNotifyPayload payload = notify->payload;
1221   SilcPacket packet = notify->packet;
1222   SilcNotifyType type = silc_notify_get_type(payload);
1223   SilcArgumentPayload args = silc_notify_get_args(payload);
1224   SilcClientEntry client_entry, client_entry2;
1225   SilcChannelEntry channel = NULL;
1226   unsigned char *tmp;
1227   SilcUInt32 tmp_len;
1228   SilcID id;
1229
1230   SILC_LOG_DEBUG(("Notify: KICKED"));
1231
1232   /* Get channel entry */
1233   if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1234                       &id.u.channel_id, sizeof(id.u.channel_id)))
1235     goto out;
1236   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1237   if (!channel)
1238     goto out;
1239
1240   /* If channel is being resolved handle notify after resolving */
1241   if (channel->internal.resolve_cmd_ident) {
1242     silc_client_unref_channel(client, conn, channel);
1243     SILC_FSM_CALL(silc_client_command_pending(
1244                                       conn, SILC_COMMAND_NONE,
1245                                       channel->internal.resolve_cmd_ident,
1246                                       silc_client_notify_wait_continue,
1247                                       notify));
1248     /* NOT REACHED */
1249   }
1250
1251   /* Get the kicked Client ID */
1252   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1253     goto out;
1254
1255   /* Find client entry */
1256   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1257   if (!client_entry)
1258     goto out;
1259
1260   /* Get kicker's Client ID */
1261   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1262     goto out;
1263
1264   /* Find kicker's client entry and if not found resolve it */
1265   client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1266   if (!client_entry2 || !client_entry2->internal.valid) {
1267     /** Resolve client */
1268     silc_client_unref_client(client, conn, client_entry);
1269     silc_client_unref_client(client, conn, client_entry2);
1270     notify->channel = channel;
1271     SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1272                   silc_client_get_client_by_id_resolve(
1273                                          client, conn, &id.u.client_id, NULL,
1274                                          silc_client_notify_resolved,
1275                                          notify));
1276     /* NOT REACHED */
1277   }
1278
1279   /* Get comment */
1280   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1281
1282   /* Remove kicked client from channel */
1283   if (client_entry != conn->local_entry) {
1284     if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
1285       goto out;
1286   }
1287
1288   /* Notify application. */
1289   NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1290
1291   /* If I was kicked from channel, remove the channel */
1292   if (client_entry == conn->local_entry) {
1293     if (conn->current_channel == channel)
1294       conn->current_channel = NULL;
1295     silc_client_empty_channel(client, conn, channel);
1296     silc_client_del_channel(client, conn, channel);
1297   }
1298
1299   silc_client_unref_client(client, conn, client_entry);
1300   silc_client_unref_client(client, conn, client_entry2);
1301
1302  out:
1303   /** Notify processed */
1304   silc_client_unref_channel(client, conn, channel);
1305   silc_fsm_next(fsm, silc_client_notify_processed);
1306   return SILC_FSM_CONTINUE;
1307 }
1308
1309 /******************************** KILLED ************************************/
1310
1311 /* Some client was killed from the network */
1312
1313 SILC_FSM_STATE(silc_client_notify_killed)
1314 {
1315   SilcClientConnection conn = fsm_context;
1316   SilcClient client = conn->client;
1317   SilcClientNotify notify = state_context;
1318   SilcNotifyPayload payload = notify->payload;
1319   SilcNotifyType type = silc_notify_get_type(payload);
1320   SilcArgumentPayload args = silc_notify_get_args(payload);
1321   SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1322   SilcChannelEntry channel_entry = NULL;
1323   SilcServerEntry server = NULL;
1324   void *entry;
1325   char *comment;
1326   SilcUInt32 comment_len;
1327   SilcID id;
1328
1329   SILC_LOG_DEBUG(("Notify: KILLED"));
1330
1331   /* Get Client ID */
1332   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1333     goto out;
1334
1335   /* Find Client entry */
1336   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1337   if (!client_entry)
1338     goto out;
1339
1340   /* Get comment */
1341   comment = silc_argument_get_arg_type(args, 2, &comment_len);
1342
1343   /* Get killer's ID */
1344   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1345     goto out;
1346
1347   if (id.type == SILC_ID_CLIENT) {
1348     /* Find Client entry */
1349     client_entry2 = silc_client_get_client_by_id(client, conn,
1350                                                  &id.u.client_id);
1351     if (!client_entry2 || !client_entry2->internal.valid) {
1352       /** Resolve client */
1353       silc_client_unref_client(client, conn, client_entry);
1354       silc_client_unref_client(client, conn, client_entry2);
1355       SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1356                                            client, conn, &id.u.client_id, NULL,
1357                                            silc_client_notify_resolved,
1358                                            notify));
1359       /* NOT REACHED */
1360     }
1361     entry = client_entry2;
1362   } else if (id.type == SILC_ID_SERVER) {
1363     /* Find Server entry */
1364     server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1365     if (!server) {
1366       /** Resolve server */
1367       SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1368                                            client, conn, &id.u.server_id,
1369                                            silc_client_notify_resolved,
1370                                            notify));
1371       /* NOT REACHED */
1372     }
1373     entry = server;
1374   } else {
1375     /* Find Channel entry */
1376     channel_entry = silc_client_get_channel_by_id(client, conn,
1377                                                   &id.u.channel_id);
1378     if (!channel_entry) {
1379       /** Resolve channel */
1380       SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1381                                     client, conn, &id.u.channel_id,
1382                                     silc_client_notify_resolved,
1383                                     notify));
1384       /* NOT REACHED */
1385     }
1386     entry = channel_entry;
1387   }
1388
1389   /* Notify application. */
1390   NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1391
1392   /* Delete the killed client */
1393   if (client_entry != conn->local_entry) {
1394     silc_client_remove_from_channels(client, conn, client_entry);
1395     client_entry->internal.valid = FALSE;
1396     silc_client_del_client(client, conn, client_entry);
1397   }
1398
1399  out:
1400   silc_client_unref_client(client, conn, client_entry);
1401   if (client_entry2)
1402     silc_client_unref_client(client, conn, client_entry2);
1403   if (server)
1404     silc_client_unref_server(client, conn, server);
1405   if (channel_entry)
1406     silc_client_unref_channel(client, conn, channel_entry);
1407
1408   /** Notify processed */
1409   silc_fsm_next(fsm, silc_client_notify_processed);
1410   return SILC_FSM_CONTINUE;
1411 }
1412
1413 /**************************** SERVER SIGNOFF ********************************/
1414
1415 /* Some server quit SILC network.  Remove its clients from channels. */
1416
1417 SILC_FSM_STATE(silc_client_notify_server_signoff)
1418 {
1419   SilcClientConnection conn = fsm_context;
1420   SilcClient client = conn->client;
1421   SilcClientNotify notify = state_context;
1422   SilcNotifyPayload payload = notify->payload;
1423   SilcNotifyType type = silc_notify_get_type(payload);
1424   SilcArgumentPayload args = silc_notify_get_args(payload);
1425   SilcClientEntry client_entry;
1426   SilcServerEntry server_entry = NULL;
1427   SilcDList clients;
1428   SilcID id;
1429   int i;
1430
1431   SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1432
1433   clients = silc_dlist_init();
1434   if (!clients)
1435     goto out;
1436
1437   /* Get server ID */
1438   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1439     goto out;
1440
1441   /* Get server, in case we have it cached */
1442   server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1443
1444   for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1445     /* Get Client ID */
1446     if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1447       goto out;
1448
1449     /* Get the client entry */
1450     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1451     if (client_entry && client_entry->internal.valid)
1452       silc_dlist_add(clients, client_entry);
1453   }
1454
1455   /* Notify application. */
1456   NOTIFY(client, conn, type, server_entry, clients);
1457
1458   /* Delete the clients */
1459   silc_dlist_start(clients);
1460   while ((client_entry = silc_dlist_get(clients))) {
1461     silc_client_remove_from_channels(client, conn, client_entry);
1462     client_entry->internal.valid = FALSE;
1463     silc_client_del_client(client, conn, client_entry);
1464   }
1465
1466  out:
1467   /** Notify processed */
1468   silc_client_unref_server(client, conn, server_entry);
1469   silc_client_list_free(client, conn, clients);
1470   silc_fsm_next(fsm, silc_client_notify_processed);
1471   return SILC_FSM_CONTINUE;
1472 }
1473
1474 /******************************** ERROR *************************************/
1475
1476 /* Some error occurred */
1477
1478 SILC_FSM_STATE(silc_client_notify_error)
1479 {
1480   SilcClientConnection conn = fsm_context;
1481   SilcClient client = conn->client;
1482   SilcClientNotify notify = state_context;
1483   SilcNotifyPayload payload = notify->payload;
1484   SilcNotifyType type = silc_notify_get_type(payload);
1485   SilcArgumentPayload args = silc_notify_get_args(payload);
1486   SilcClientEntry client_entry;
1487   unsigned char *tmp;
1488   SilcUInt32 tmp_len;
1489   SilcID id;
1490   SilcStatus error;
1491
1492   /* Get error */
1493   tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1494   if (!tmp && tmp_len != 1)
1495     goto out;
1496   error = (SilcStatus)tmp[0];
1497
1498   SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1499
1500   /* Handle the error */
1501   if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1502     if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1503       goto out;
1504     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1505     if (client_entry && client_entry != conn->local_entry) {
1506       silc_client_remove_from_channels(client, conn, client_entry);
1507       silc_client_del_client(client, conn, client_entry);
1508       silc_client_unref_client(client, conn, client_entry);
1509     }
1510   }
1511
1512   /* Notify application. */
1513   NOTIFY(client, conn, type, error);
1514
1515  out:
1516   /** Notify processed */
1517   silc_fsm_next(fsm, silc_client_notify_processed);
1518   return SILC_FSM_CONTINUE;
1519 }
1520
1521 /******************************** WATCH *************************************/
1522
1523 /* Received notify about some client we are watching */
1524
1525 SILC_FSM_STATE(silc_client_notify_watch)
1526 {
1527   SilcClientConnection conn = fsm_context;
1528   SilcClient client = conn->client;
1529   SilcClientNotify notify = state_context;
1530   SilcNotifyPayload payload = notify->payload;
1531   SilcNotifyType type = silc_notify_get_type(payload);
1532   SilcArgumentPayload args = silc_notify_get_args(payload);
1533   SilcClientEntry client_entry = NULL;
1534   SilcNotifyType ntype = 0;
1535   unsigned char *pk, *tmp;
1536   SilcUInt32 mode, pk_len, tmp_len;
1537   SilcPublicKey public_key = NULL;
1538   SilcID id;
1539
1540   SILC_LOG_DEBUG(("Notify: WATCH"));
1541
1542   /* Get sender Client ID */
1543   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1544     goto out;
1545
1546   /* Find client entry and if not found resolve it */
1547   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1548   if (!client_entry || !client_entry->internal.valid) {
1549     /** Resolve client */
1550     silc_client_unref_client(client, conn, client_entry);
1551     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1552                                          client, conn, &id.u.client_id, NULL,
1553                                          silc_client_notify_resolved,
1554                                          notify));
1555     /* NOT REACHED */
1556   }
1557
1558   /* Get user mode */
1559   tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1560   if (!tmp || tmp_len != 4)
1561     goto out;
1562   SILC_GET32_MSB(mode, tmp);
1563
1564   /* Get notify type */
1565   tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1566   if (tmp && tmp_len != 2)
1567     goto out;
1568   if (tmp)
1569     SILC_GET16_MSB(ntype, tmp);
1570
1571   /* Get nickname */
1572   tmp = silc_argument_get_arg_type(args, 2, NULL);
1573   if (tmp) {
1574     char *tmp_nick = NULL;
1575
1576     silc_client_nickname_parse(client, conn, client_entry->nickname,
1577                                &tmp_nick);
1578
1579     /* If same nick, the client was new to us and has become "present"
1580        to network.  Send NULL as nick to application. */
1581     if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1582       tmp = NULL;
1583
1584     silc_free(tmp_nick);
1585   }
1586
1587   /* Get public key, if present */
1588   pk = silc_argument_get_arg_type(args, 5, &pk_len);
1589   if (pk && !client_entry->public_key) {
1590     if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1591       client_entry->public_key = public_key;
1592       public_key = NULL;
1593     }
1594   }
1595
1596   /* Notify application. */
1597   NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1598          client_entry->public_key);
1599
1600   client_entry->mode = mode;
1601
1602   /* Remove client that left the network. */
1603   if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1604       ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1605       ntype == SILC_NOTIFY_TYPE_KILLED) {
1606     silc_client_remove_from_channels(client, conn, client_entry);
1607     client_entry->internal.valid = FALSE;
1608     silc_client_del_client(client, conn, client_entry);
1609   }
1610
1611   if (public_key)
1612     silc_pkcs_public_key_free(public_key);
1613
1614  out:
1615   /** Notify processed */
1616   silc_client_unref_client(client, conn, client_entry);
1617   silc_fsm_next(fsm, silc_client_notify_processed);
1618   return SILC_FSM_CONTINUE;
1619 }