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