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