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