More client library rewrites (key agreement, plus other).
[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 - 2006 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(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"));
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   /* 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     return SILC_FSM_FINISH;
210     break;
211   }
212
213   return 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   return 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   return 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
283   /* If channel is being resolved handle notify after resolving */
284   if (channel->internal.resolve_cmd_ident) {
285     silc_client_unref_channel(client, conn, channel);
286     SILC_FSM_CALL(silc_client_command_pending(
287                                       conn, SILC_COMMAND_NONE,
288                                       channel->internal.resolve_cmd_ident,
289                                       silc_client_notify_wait_continue,
290                                       notify));
291     /* NOT REACHED */
292   }
293
294   /* Get sender Client ID */
295   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
296     goto out;
297
298   /* Find Client entry and if not found query it */
299   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
300   if (!client_entry || !client_entry->nickname[0]) {
301     /** Resolve client */
302     silc_client_unref_client(client, conn, client_entry);
303     notify->channel = channel;
304     SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
305                   silc_client_get_client_by_id_resolve(
306                                          client, conn, &id.u.client_id, NULL,
307                                          silc_client_notify_resolved,
308                                          notify));
309     /* NOT REACHED */
310   }
311
312   /* Notify application */
313   NOTIFY(client, conn, type, channel, tmp, client_entry);
314
315   silc_client_unref_client(client, conn, client_entry);
316
317  out:
318   /** Notify processed */
319   silc_client_unref_channel(client, conn, channel);
320   silc_fsm_next(fsm, silc_client_notify_processed);
321   return SILC_FSM_CONTINUE;
322 }
323
324 /********************************** JOIN ************************************/
325
326 /* Someone joined a channel */
327
328 SILC_FSM_STATE(silc_client_notify_join)
329 {
330   SilcClientConnection conn = fsm_context;
331   SilcClient client = conn->client;
332   SilcClientNotify notify = state_context;
333   SilcNotifyPayload payload = notify->payload;
334   SilcNotifyType type = silc_notify_get_type(payload);
335   SilcArgumentPayload args = silc_notify_get_args(payload);
336   SilcClientEntry client_entry;
337   SilcChannelEntry channel = NULL;
338   SilcID id;
339
340   SILC_LOG_DEBUG(("Notify: JOIN"));
341
342   /* Get Channel ID */
343   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
344     goto out;
345
346   /* Get channel entry */
347   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
348   if (!channel)
349     goto out;
350
351   /* If channel is being resolved handle notify after resolving */
352   if (channel->internal.resolve_cmd_ident) {
353     silc_client_unref_channel(client, conn, channel);
354     SILC_FSM_CALL(silc_client_command_pending(
355                                       conn, SILC_COMMAND_NONE,
356                                       channel->internal.resolve_cmd_ident,
357                                       silc_client_notify_wait_continue,
358                                       notify));
359     /* NOT REACHED */
360   }
361
362   /* Get Client ID */
363   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
364     goto out;
365
366   /* Find Client entry and if not found query it */
367   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
368   if (!client_entry || !client_entry->nickname[0] ||
369       !client_entry->username[0]) {
370     /** Resolve client */
371     silc_client_unref_client(client, conn, client_entry);
372     notify->channel = channel;
373     SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
374                   silc_client_get_client_by_id_resolve(
375                                          client, conn, &id.u.client_id, NULL,
376                                          silc_client_notify_resolved,
377                                          notify));
378     /* NOT REACHED */
379   }
380
381   if (client_entry != conn->local_entry)
382     silc_client_nickname_format(client, conn, client_entry);
383
384   /* Join the client to channel */
385   if (!silc_client_add_to_channel(client, conn, channel, client_entry, 0))
386     goto out;
387
388   /* Notify application. */
389   NOTIFY(client, conn, type, client_entry, channel);
390
391   silc_client_unref_client(client, conn, client_entry);
392
393  out:
394   /** Notify processed */
395   silc_client_unref_channel(client, conn, channel);
396   silc_fsm_next(fsm, silc_client_notify_processed);
397   return SILC_FSM_CONTINUE;
398 }
399
400 /********************************** LEAVE ***********************************/
401
402 /* Someone left a channel */
403
404 SILC_FSM_STATE(silc_client_notify_leave)
405 {
406   SilcClientConnection conn = fsm_context;
407   SilcClient client = conn->client;
408   SilcClientNotify notify = state_context;
409   SilcNotifyPayload payload = notify->payload;
410   SilcPacket packet = notify->packet;
411   SilcNotifyType type = silc_notify_get_type(payload);
412   SilcArgumentPayload args = silc_notify_get_args(payload);
413   SilcClientEntry client_entry = NULL;
414   SilcChannelEntry channel = NULL;
415   SilcID id;
416
417   SILC_LOG_DEBUG(("Notify: LEAVE"));
418
419   /* Get channel entry */
420   if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
421                       &id.u.channel_id, sizeof(id.u.channel_id)))
422     goto out;
423   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
424   if (!channel)
425     goto out;
426
427   /* If channel is being resolved handle notify after resolving */
428   if (channel->internal.resolve_cmd_ident) {
429     silc_client_unref_channel(client, conn, channel);
430     SILC_FSM_CALL(silc_client_command_pending(
431                                       conn, SILC_COMMAND_NONE,
432                                       channel->internal.resolve_cmd_ident,
433                                       silc_client_notify_wait_continue,
434                                       notify));
435     /* NOT REACHED */
436   }
437
438   /* Get Client ID */
439   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
440     goto out;
441
442   /* Find Client entry */
443   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
444   if (!client_entry)
445     goto out;
446
447   /* Remove client from channel */
448   silc_client_remove_from_channel(client, conn, channel, client_entry);
449
450   /* Notify application. */
451   NOTIFY(client, conn, type, client_entry, channel);
452
453   silc_client_unref_client(client, conn, client_entry);
454
455  out:
456   /** Notify processed */
457   silc_client_unref_channel(client, conn, channel);
458   silc_fsm_next(fsm, silc_client_notify_processed);
459   return SILC_FSM_CONTINUE;
460 }
461
462 /********************************* SIGNOFF **********************************/
463
464 /* Someone quit SILC network */
465
466 SILC_FSM_STATE(silc_client_notify_signoff)
467 {
468   SilcClientConnection conn = fsm_context;
469   SilcClient client = conn->client;
470   SilcClientNotify notify = state_context;
471   SilcNotifyPayload payload = notify->payload;
472   SilcNotifyType type = silc_notify_get_type(payload);
473   SilcArgumentPayload args = silc_notify_get_args(payload);
474   SilcClientEntry client_entry;
475    unsigned char *tmp;
476   SilcUInt32 tmp_len;
477   SilcID id;
478
479   SILC_LOG_DEBUG(("Notify: SIGNOFF"));
480
481   /* Get Client ID */
482   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
483     goto out;
484
485   /* Find Client entry */
486   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
487   if (!client_entry)
488     goto out;
489
490   /* Get signoff message */
491   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
492   if (tmp_len > 128)
493     tmp[128] = '\0';
494
495   /* Notify application */
496   NOTIFY(client, conn, type, client_entry, tmp);
497
498   /* Delete client */
499   silc_client_del_client(client, conn, client_entry);
500   silc_client_unref_client(client, conn, client_entry);
501
502  out:
503   /** Notify processed */
504   silc_fsm_next(fsm, silc_client_notify_processed);
505   return SILC_FSM_CONTINUE;
506 }
507
508 /******************************** TOPIC_SET *********************************/
509
510 /* Someone set topic on a channel */
511
512 SILC_FSM_STATE(silc_client_notify_topic_set)
513 {
514   SilcClientConnection conn = fsm_context;
515   SilcClient client = conn->client;
516   SilcClientNotify notify = state_context;
517   SilcNotifyPayload payload = notify->payload;
518   SilcPacket packet = notify->packet;
519   SilcNotifyType type = silc_notify_get_type(payload);
520   SilcArgumentPayload args = silc_notify_get_args(payload);
521   SilcClientEntry client_entry = NULL;
522   SilcChannelEntry channel = NULL, channel_entry = NULL;
523   SilcServerEntry server = NULL;
524   void *entry;
525   unsigned char *tmp;
526   SilcUInt32 tmp_len;
527   SilcID id;
528
529   SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
530
531   /* Get channel entry */
532   if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
533                       &id.u.channel_id, sizeof(id.u.channel_id)))
534     goto out;
535   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
536   if (!channel)
537     goto out;
538
539   /* If channel is being resolved handle notify after resolving */
540   if (channel->internal.resolve_cmd_ident) {
541     silc_client_unref_channel(client, conn, channel);
542     SILC_FSM_CALL(silc_client_command_pending(
543                                       conn, SILC_COMMAND_NONE,
544                                       channel->internal.resolve_cmd_ident,
545                                       silc_client_notify_wait_continue,
546                                       notify));
547     /* NOT REACHED */
548   }
549
550   /* Get ID */
551   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
552     goto out;
553
554   /* Get topic */
555   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
556   if (!tmp)
557     goto out;
558
559   if (id.type == SILC_ID_CLIENT) {
560     /* Find Client entry */
561     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
562     if (!client_entry || !client_entry->nickname[0]) {
563       /** Resolve client */
564       silc_client_unref_client(client, conn, client_entry);
565       notify->channel = channel;
566       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
567                     silc_client_get_client_by_id_resolve(
568                                            client, conn, &id.u.client_id, NULL,
569                                            silc_client_notify_resolved,
570                                            notify));
571       /* NOT REACHED */
572     }
573     entry = client_entry;
574   } else if (id.type == SILC_ID_SERVER) {
575     /* Find Server entry */
576     server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
577     if (!server) {
578       /** Resolve server */
579       notify->channel = channel;
580       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
581                     silc_client_get_server_by_id_resolve(
582                                            client, conn, &id.u.server_id,
583                                            silc_client_notify_resolved,
584                                            notify));
585       /* NOT REACHED */
586     }
587     entry = server;
588   } else {
589     /* Find Channel entry */
590     channel_entry = silc_client_get_channel_by_id(client, conn,
591                                                   &id.u.channel_id);
592     if (!channel_entry) {
593       /** Resolve channel */
594       notify->channel = channel;
595       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
596                     silc_client_get_channel_by_id_resolve(
597                                     client, conn, &id.u.channel_id,
598                                     silc_client_notify_resolved,
599                                     notify));
600       /* NOT REACHED */
601     }
602     entry = channel_entry;
603   }
604
605   silc_free(channel->topic);
606   channel->topic = silc_memdup(tmp, strlen(tmp));
607
608   /* Notify application. */
609   NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
610
611   if (client_entry)
612     silc_client_unref_client(client, conn, client_entry);
613   if (server)
614     silc_client_unref_server(client, conn, server);
615   if (channel_entry)
616     silc_client_unref_channel(client, conn, channel_entry);
617
618  out:
619   /** Notify processed */
620   silc_client_unref_channel(client, conn, channel);
621   silc_fsm_next(fsm, silc_client_notify_processed);
622   return SILC_FSM_CONTINUE;
623 }
624
625 /****************************** NICK_CHANGE *********************************/
626
627 /* Someone changed their nickname on a channel */
628
629 SILC_FSM_STATE(silc_client_notify_nick_change)
630 {
631   SilcClientConnection conn = fsm_context;
632   SilcClient client = conn->client;
633   SilcClientNotify notify = state_context;
634   SilcNotifyPayload payload = notify->payload;
635   SilcNotifyType type = silc_notify_get_type(payload);
636   SilcArgumentPayload args = silc_notify_get_args(payload);
637   SilcClientEntry client_entry = NULL;
638   unsigned char *tmp, *nick, oldnick[128 + 1];
639   SilcUInt32 tmp_len;
640   SilcID id, id2;
641
642   SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
643
644   /* Get ID */
645   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
646     goto out;
647
648   /* Ignore my ID */
649   if (conn->local_id &&
650       SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
651     goto out;
652
653   /* Get new Client ID */
654   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
655     goto out;
656
657   /* Ignore my ID */
658   if (conn->local_id &&
659       SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
660     goto out;
661
662   /* Find old Client entry */
663   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
664   if (!client_entry || !client_entry->nickname[0]) {
665     /** Resolve client */
666     silc_client_unref_client(client, conn, client_entry);
667     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
668                                          client, conn, &id.u.client_id, NULL,
669                                          silc_client_notify_resolved,
670                                          notify));
671     /* NOT REACHED */
672   }
673
674   /* Take the new nickname */
675   tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
676   if (!tmp)
677     goto out;
678
679   /* Check whether nickname changed at all.  It is possible that nick
680      change notify is received but nickname didn't change, only the
681      ID changes.  If Client ID hash match, nickname didn't change. */
682   if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
683       silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
684     /* Nickname didn't change.  Update only Client ID.  We don't notify
685        application because nickname didn't change. */
686     silc_mutex_lock(conn->internal->lock);
687     silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
688                                    &id2.u.client_id, NULL, FALSE);
689     silc_mutex_unlock(conn->internal->lock);
690     goto out;
691   }
692
693   /* Normalize nickname */
694   nick = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8, 128, NULL);
695   if (!nick)
696     goto out;
697
698   /* Update nickname */
699   silc_mutex_lock(conn->internal->lock);
700   if (!silc_idcache_update_by_context(conn->internal->client_cache,
701                                       client_entry, NULL, nick, TRUE)) {
702     silc_free(nick);
703     silc_mutex_unlock(conn->internal->lock);
704     goto out;
705   }
706   silc_mutex_unlock(conn->internal->lock);
707   memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
708   memcpy(client_entry->nickname, tmp, tmp_len);
709   client_entry->nickname_normalized = nick;
710   silc_client_nickname_format(client, conn, client_entry);
711
712   /* Notify application */
713   NOTIFY(client, conn, type, client_entry, client_entry->nickname, oldnick);
714
715  out:
716   /** Notify processed */
717   silc_client_unref_client(client, conn, client_entry);
718   silc_fsm_next(fsm, silc_client_notify_processed);
719   return SILC_FSM_CONTINUE;
720 }
721
722 /****************************** CMODE_CHANGE ********************************/
723
724 /* Someone changed channel mode */
725
726 SILC_FSM_STATE(silc_client_notify_cmode_change)
727 {
728   SilcClientConnection conn = fsm_context;
729   SilcClient client = conn->client;
730   SilcClientNotify notify = state_context;
731   SilcNotifyPayload payload = notify->payload;
732   SilcPacket packet = notify->packet;
733   SilcNotifyType type = silc_notify_get_type(payload);
734   SilcArgumentPayload args = silc_notify_get_args(payload);
735   SilcClientEntry client_entry = NULL;
736   SilcChannelEntry channel = NULL, channel_entry = NULL;
737   SilcServerEntry server = NULL;
738   void *entry;
739   unsigned char *tmp;
740   SilcUInt32 tmp_len, mode;
741   SilcID id;
742   char *passphrase, *cipher, *hmac;
743   SilcPublicKey founder_key = NULL;
744   SilcDList chpks = NULL;
745
746   SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
747
748   /* Get channel entry */
749   if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
750                       &id.u.channel_id, sizeof(id.u.channel_id)))
751     goto out;
752   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
753   if (!channel)
754     goto out;
755
756   /* If channel is being resolved handle notify after resolving */
757   if (channel->internal.resolve_cmd_ident) {
758     silc_client_unref_channel(client, conn, channel);
759     SILC_FSM_CALL(silc_client_command_pending(
760                                       conn, SILC_COMMAND_NONE,
761                                       channel->internal.resolve_cmd_ident,
762                                       silc_client_notify_wait_continue,
763                                       notify));
764     /* NOT REACHED */
765   }
766
767   /* Get the mode */
768   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
769   if (!tmp)
770     goto out;
771   SILC_GET32_MSB(mode, tmp);
772
773   /* Get ID */
774   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
775     goto out;
776
777   if (id.type == SILC_ID_CLIENT) {
778     /* Find Client entry */
779     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
780     if (!client_entry || !client_entry->nickname[0]) {
781       /** Resolve client */
782       silc_client_unref_client(client, conn, client_entry);
783       notify->channel = channel;
784       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
785                     silc_client_get_client_by_id_resolve(
786                                            client, conn, &id.u.client_id, NULL,
787                                            silc_client_notify_resolved,
788                                            notify));
789       /* NOT REACHED */
790     }
791     entry = client_entry;
792   } else if (id.type == SILC_ID_SERVER) {
793     /* Find Server entry */
794     server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
795     if (!server) {
796       /** Resolve server */
797       notify->channel = channel;
798       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
799                     silc_client_get_server_by_id_resolve(
800                                            client, conn, &id.u.server_id,
801                                            silc_client_notify_resolved,
802                                            notify));
803       /* NOT REACHED */
804     }
805     entry = server;
806   } else {
807     /* Find Channel entry */
808     channel_entry = silc_client_get_channel_by_id(client, conn,
809                                                   &id.u.channel_id);
810     if (!channel_entry) {
811       /** Resolve channel */
812       notify->channel = channel;
813       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
814                     silc_client_get_channel_by_id_resolve(
815                                     client, conn, &id.u.channel_id,
816                                     silc_client_notify_resolved,
817                                     notify));
818       /* NOT REACHED */
819     }
820     entry = channel_entry;
821   }
822
823   /* Get the channel founder key if it was set */
824   tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
825   if (tmp) {
826     if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key))
827       goto out;
828     if (!channel->founder_key) {
829       channel->founder_key = founder_key;
830       founder_key = NULL;
831     }
832   }
833
834   /* Get the cipher */
835   cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
836
837   /* Get the hmac */
838   hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
839   if (hmac) {
840     unsigned char hash[SILC_HASH_MAXLEN];
841     SilcHmac newhmac;
842
843     if (!silc_hmac_alloc(hmac, NULL, &newhmac))
844       goto out;
845
846     /* Get HMAC key from the old HMAC context, and update it to the new one */
847     tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
848     if (tmp) {
849       silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
850       silc_hmac_set_key(newhmac, hash,
851                         silc_hash_len(silc_hmac_get_hash(newhmac)));
852       if (channel->internal.hmac)
853         silc_hmac_free(channel->internal.hmac);
854       channel->internal.hmac = newhmac;
855       memset(hash, 0, sizeof(hash));
856     }
857   }
858
859   /* Get the passphrase if it was set */
860   passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
861
862   /* Get user limit */
863   tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
864   if (tmp && tmp_len == 4)
865     SILC_GET32_MSB(channel->user_limit, tmp);
866   if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
867     channel->user_limit = 0;
868
869   /* Save the new mode */
870   channel->mode = mode;
871
872   /* Get the channel public key that was added or removed */
873   tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
874   if (tmp)
875     chpks = silc_argument_list_parse_decoded(tmp, tmp_len,
876                                              SILC_ARGUMENT_PUBLIC_KEY);
877
878   /* Notify application. */
879   NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
880          passphrase, channel->founder_key, chpks, channel);
881
882  out:
883   if (founder_key)
884     silc_pkcs_public_key_free(founder_key);
885   if (chpks)
886     silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
887   if (client_entry)
888     silc_client_unref_client(client, conn, client_entry);
889   if (server)
890     silc_client_unref_server(client, conn, server);
891   if (channel_entry)
892     silc_client_unref_channel(client, conn, channel_entry);
893   silc_client_unref_channel(client, conn, channel);
894
895   /** Notify processed */
896   silc_fsm_next(fsm, silc_client_notify_processed);
897   return SILC_FSM_CONTINUE;
898 }
899
900 /***************************** CUMODE_CHANGE ********************************/
901
902 /* Someone changed a user's mode on a channel */
903
904 SILC_FSM_STATE(silc_client_notify_cumode_change)
905 {
906   SilcClientConnection conn = fsm_context;
907   SilcClient client = conn->client;
908   SilcClientNotify notify = state_context;
909   SilcNotifyPayload payload = notify->payload;
910   SilcPacket packet = notify->packet;
911   SilcNotifyType type = silc_notify_get_type(payload);
912   SilcArgumentPayload args = silc_notify_get_args(payload);
913   SilcClientEntry client_entry = NULL, client_entry2 = NULL;
914   SilcChannelEntry channel = NULL, channel_entry = NULL;
915   SilcServerEntry server = NULL;
916   SilcChannelUser chu;
917   void *entry;
918   unsigned char *tmp;
919   SilcUInt32 tmp_len, mode;
920   SilcID id, id2;
921
922   SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
923
924   /* Get channel entry */
925   if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
926                       &id.u.channel_id, sizeof(id.u.channel_id)))
927     goto out;
928   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
929   if (!channel)
930     goto out;
931
932   /* If channel is being resolved handle notify after resolving */
933   if (channel->internal.resolve_cmd_ident) {
934     silc_client_unref_channel(client, conn, channel);
935     SILC_FSM_CALL(silc_client_command_pending(
936                                       conn, SILC_COMMAND_NONE,
937                                       channel->internal.resolve_cmd_ident,
938                                       silc_client_notify_wait_continue,
939                                       notify));
940     /* NOT REACHED */
941   }
942
943   /* Get target Client ID */
944   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
945     goto out;
946
947   /* Find target Client entry */
948   client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
949   if (!client_entry2 || !client_entry2->nickname[0]) {
950     /** Resolve client */
951     silc_client_unref_client(client, conn, client_entry2);
952     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
953                                          client, conn, &id2.u.client_id, NULL,
954                                          silc_client_notify_resolved,
955                                          notify));
956     /* NOT REACHED */
957   }
958
959   /* Get the mode */
960   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
961   if (!tmp)
962     goto out;
963   SILC_GET32_MSB(mode, tmp);
964
965   /* Get ID */
966   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
967     goto out;
968
969   if (id.type == SILC_ID_CLIENT) {
970     /* Find Client entry */
971     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
972     if (!client_entry || !client_entry->nickname[0]) {
973       /** Resolve client */
974       silc_client_unref_client(client, conn, client_entry);
975       notify->channel = channel;
976       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
977                     silc_client_get_client_by_id_resolve(
978                                            client, conn, &id.u.client_id, NULL,
979                                            silc_client_notify_resolved,
980                                            notify));
981       /* NOT REACHED */
982     }
983     entry = client_entry;
984   } else if (id.type == SILC_ID_SERVER) {
985     /* Find Server entry */
986     server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
987     if (!server) {
988       /** Resolve server */
989       notify->channel = channel;
990       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
991                     silc_client_get_server_by_id_resolve(
992                                            client, conn, &id.u.server_id,
993                                            silc_client_notify_resolved,
994                                            notify));
995       /* NOT REACHED */
996     }
997     entry = server;
998   } else {
999     /* Find Channel entry */
1000     channel_entry = silc_client_get_channel_by_id(client, conn,
1001                                                   &id.u.channel_id);
1002     if (!channel_entry) {
1003       /** Resolve channel */
1004       notify->channel = channel;
1005       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1006                     silc_client_get_channel_by_id_resolve(
1007                                     client, conn, &id.u.channel_id,
1008                                     silc_client_notify_resolved,
1009                                     notify));
1010       /* NOT REACHED */
1011     }
1012     entry = channel_entry;
1013   }
1014
1015   /* Save the mode */
1016   chu = silc_client_on_channel(channel, client_entry2);
1017   if (chu)
1018     chu->mode = mode;
1019
1020   /* Notify application. */
1021   NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1022
1023  out:
1024   silc_client_unref_client(client, conn, client_entry2);
1025   if (client_entry)
1026     silc_client_unref_client(client, conn, client_entry);
1027   if (server)
1028     silc_client_unref_server(client, conn, server);
1029   if (channel_entry)
1030     silc_client_unref_channel(client, conn, channel_entry);
1031   silc_client_unref_channel(client, conn, channel);
1032
1033   /** Notify processed */
1034   silc_fsm_next(fsm, silc_client_notify_processed);
1035   return SILC_FSM_CONTINUE;
1036 }
1037
1038 /********************************* MOTD *************************************/
1039
1040 /* Received Message of the day */
1041
1042 SILC_FSM_STATE(silc_client_notify_motd)
1043 {
1044   SilcClientConnection conn = fsm_context;
1045   SilcClient client = conn->client;
1046   SilcClientNotify notify = state_context;
1047   SilcNotifyPayload payload = notify->payload;
1048   SilcNotifyType type = silc_notify_get_type(payload);
1049   SilcArgumentPayload args = silc_notify_get_args(payload);
1050   unsigned char *tmp;
1051   SilcUInt32 tmp_len;
1052
1053   SILC_LOG_DEBUG(("Notify: MOTD"));
1054
1055   /* Get motd */
1056   tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1057   if (!tmp)
1058     goto out;
1059
1060   /* Notify application */
1061   NOTIFY(client, conn, type, tmp);
1062
1063  out:
1064   /** Notify processed */
1065   silc_fsm_next(fsm, silc_client_notify_processed);
1066   return SILC_FSM_CONTINUE;
1067 }
1068
1069 /**************************** CHANNEL CHANGE ********************************/
1070
1071 /* Router has enforced a new ID to a channel, change it */
1072
1073 SILC_FSM_STATE(silc_client_notify_channel_change)
1074 {
1075   SilcClientConnection conn = fsm_context;
1076   SilcClient client = conn->client;
1077   SilcClientNotify notify = state_context;
1078   SilcNotifyPayload payload = notify->payload;
1079   SilcNotifyType type = silc_notify_get_type(payload);
1080   SilcArgumentPayload args = silc_notify_get_args(payload);
1081   SilcChannelEntry channel = NULL;
1082   SilcID id;
1083
1084   SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1085
1086   /* Get the old ID */
1087   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1088     goto out;
1089
1090   /* Get the channel entry */
1091   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1092   if (!channel)
1093     goto out;
1094
1095   /* If channel is being resolved handle notify after resolving */
1096   if (channel->internal.resolve_cmd_ident) {
1097     silc_client_unref_channel(client, conn, channel);
1098     SILC_FSM_CALL(silc_client_command_pending(
1099                                       conn, SILC_COMMAND_NONE,
1100                                       channel->internal.resolve_cmd_ident,
1101                                       silc_client_notify_wait_continue,
1102                                       notify));
1103     /* NOT REACHED */
1104   }
1105
1106   /* Get the new ID */
1107   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1108     goto out;
1109
1110   /* Replace the Channel ID */
1111   if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1112     goto out;
1113
1114   /* Notify application */
1115   NOTIFY(client, conn, type, channel, channel);
1116
1117  out:
1118   /** Notify processed */
1119   silc_client_unref_channel(client, conn, channel);
1120   silc_fsm_next(fsm, silc_client_notify_processed);
1121   return SILC_FSM_CONTINUE;
1122 }
1123
1124 /******************************** KICKED ************************************/
1125
1126 /* Some client was kicked from a channel */
1127
1128 SILC_FSM_STATE(silc_client_notify_kicked)
1129 {
1130   SilcClientConnection conn = fsm_context;
1131   SilcClient client = conn->client;
1132   SilcClientNotify notify = state_context;
1133   SilcNotifyPayload payload = notify->payload;
1134   SilcPacket packet = notify->packet;
1135   SilcNotifyType type = silc_notify_get_type(payload);
1136   SilcArgumentPayload args = silc_notify_get_args(payload);
1137   SilcClientEntry client_entry, client_entry2;
1138   SilcChannelEntry channel = NULL;
1139   SilcChannelUser chu;
1140   unsigned char *tmp;
1141   SilcUInt32 tmp_len;
1142   SilcID id;
1143
1144   SILC_LOG_DEBUG(("Notify: KICKED"));
1145
1146   /* Get channel entry */
1147   if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1148                       &id.u.channel_id, sizeof(id.u.channel_id)))
1149     goto out;
1150   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1151   if (!channel)
1152     goto out;
1153
1154   /* If channel is being resolved handle notify after resolving */
1155   if (channel->internal.resolve_cmd_ident) {
1156     silc_client_unref_channel(client, conn, channel);
1157     SILC_FSM_CALL(silc_client_command_pending(
1158                                       conn, SILC_COMMAND_NONE,
1159                                       channel->internal.resolve_cmd_ident,
1160                                       silc_client_notify_wait_continue,
1161                                       notify));
1162     /* NOT REACHED */
1163   }
1164
1165   /* Get Client ID */
1166   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1167     goto out;
1168
1169   /* Find Client entry */
1170   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1171   if (!client_entry)
1172     goto out;
1173
1174   /* Get kicker's Client ID */
1175   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1176     goto out;
1177
1178   /* Find kicker's client entry and if not found resolve it */
1179   client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1180   if (!client_entry2 || !client_entry2->nickname[0]) {
1181     /** Resolve client */
1182     silc_client_unref_client(client, conn, client_entry);
1183     silc_client_unref_client(client, conn, client_entry2);
1184     notify->channel = channel;
1185     SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1186                   silc_client_get_client_by_id_resolve(
1187                                          client, conn, &id.u.client_id, NULL,
1188                                          silc_client_notify_resolved,
1189                                          notify));
1190     /* NOT REACHED */
1191   }
1192
1193   /* Get comment */
1194   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1195
1196   /* Remove kicked client from channel */
1197   if (client_entry != conn->local_entry) {
1198     chu = silc_client_on_channel(channel, client_entry);
1199     if (chu) {
1200       silc_hash_table_del(client_entry->channels, channel);
1201       silc_hash_table_del(channel->user_list, client_entry);
1202       silc_free(chu);
1203     }
1204   }
1205
1206   /* Notify application. */
1207   NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1208
1209   /* If I was kicked from channel, remove the channel */
1210   if (client_entry == conn->local_entry) {
1211     if (conn->current_channel == channel)
1212       conn->current_channel = NULL;
1213     silc_client_del_channel(client, conn, channel);
1214   }
1215
1216   silc_client_unref_client(client, conn, client_entry);
1217   silc_client_unref_client(client, conn, client_entry2);
1218
1219  out:
1220   /** Notify processed */
1221   silc_client_unref_channel(client, conn, channel);
1222   silc_fsm_next(fsm, silc_client_notify_processed);
1223   return SILC_FSM_CONTINUE;
1224 }
1225
1226 /******************************** KILLED ************************************/
1227
1228 /* Some client was killed from the network */
1229
1230 SILC_FSM_STATE(silc_client_notify_killed)
1231 {
1232   SilcClientConnection conn = fsm_context;
1233   SilcClient client = conn->client;
1234   SilcClientNotify notify = state_context;
1235   SilcNotifyPayload payload = notify->payload;
1236   SilcNotifyType type = silc_notify_get_type(payload);
1237   SilcArgumentPayload args = silc_notify_get_args(payload);
1238   SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1239   SilcChannelEntry channel_entry = NULL;
1240   SilcServerEntry server = NULL;
1241   void *entry;
1242   char *comment;
1243   SilcUInt32 comment_len;
1244   SilcID id;
1245
1246   SILC_LOG_DEBUG(("Notify: KILLED"));
1247
1248   /* Get Client ID */
1249   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1250     goto out;
1251
1252   /* Find Client entry */
1253   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1254   if (!client_entry)
1255     goto out;
1256
1257   /* Get comment */
1258   comment = silc_argument_get_arg_type(args, 2, &comment_len);
1259
1260   /* Get killer's ID */
1261   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1262     goto out;
1263
1264   if (id.type == SILC_ID_CLIENT) {
1265     /* Find Client entry */
1266     client_entry2 = silc_client_get_client_by_id(client, conn,
1267                                                  &id.u.client_id);
1268     if (!client_entry2 || !client_entry2->nickname[0]) {
1269       /** Resolve client */
1270       silc_client_unref_client(client, conn, client_entry);
1271       silc_client_unref_client(client, conn, client_entry2);
1272       SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1273                                            client, conn, &id.u.client_id, NULL,
1274                                            silc_client_notify_resolved,
1275                                            notify));
1276       /* NOT REACHED */
1277     }
1278     entry = client_entry2;
1279   } else if (id.type == SILC_ID_SERVER) {
1280     /* Find Server entry */
1281     server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1282     if (!server) {
1283       /** Resolve server */
1284       SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1285                                            client, conn, &id.u.server_id,
1286                                            silc_client_notify_resolved,
1287                                            notify));
1288       /* NOT REACHED */
1289     }
1290     entry = server;
1291   } else {
1292     /* Find Channel entry */
1293     channel_entry = silc_client_get_channel_by_id(client, conn,
1294                                                   &id.u.channel_id);
1295     if (!channel_entry) {
1296       /** Resolve channel */
1297       SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1298                                     client, conn, &id.u.channel_id,
1299                                     silc_client_notify_resolved,
1300                                     notify));
1301       /* NOT REACHED */
1302     }
1303     entry = channel_entry;
1304   }
1305
1306   /* Notify application. */
1307   NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1308
1309   /* Delete the killed client */
1310   if (client_entry != conn->local_entry)
1311     silc_client_del_client(client, conn, client_entry);
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: 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_del_client(client, conn, client_entry);
1369
1370  out:
1371   /** Notify processed */
1372   silc_client_list_free(client, conn, clients);
1373   silc_fsm_next(fsm, silc_client_notify_processed);
1374   return SILC_FSM_CONTINUE;
1375 }
1376
1377 /******************************** ERROR *************************************/
1378
1379 /* Some error occurred */
1380
1381 SILC_FSM_STATE(silc_client_notify_error)
1382 {
1383   SilcClientConnection conn = fsm_context;
1384   SilcClient client = conn->client;
1385   SilcClientNotify notify = state_context;
1386   SilcNotifyPayload payload = notify->payload;
1387   SilcNotifyType type = silc_notify_get_type(payload);
1388   SilcArgumentPayload args = silc_notify_get_args(payload);
1389   SilcClientEntry client_entry;
1390   unsigned char *tmp;
1391   SilcUInt32 tmp_len;
1392   SilcID id;
1393   SilcStatus error;
1394
1395   /* Get error */
1396   tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1397   if (!tmp && tmp_len != 1)
1398     goto out;
1399   error = (SilcStatus)tmp[0];
1400
1401   SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1402
1403   /* Handle the error */
1404   if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1405     if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1406       goto out;
1407     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1408     if (client_entry) {
1409       silc_client_del_client(client, conn, client_entry);
1410       silc_client_unref_client(client, conn, client_entry);
1411     }
1412   }
1413
1414   /* Notify application. */
1415   NOTIFY(client, conn, type, error);
1416
1417  out:
1418   /** Notify processed */
1419   silc_fsm_next(fsm, silc_client_notify_processed);
1420   return SILC_FSM_CONTINUE;
1421 }
1422
1423 /******************************** WATCH *************************************/
1424
1425 /* Received notify about some client we are watching */
1426
1427 SILC_FSM_STATE(silc_client_notify_watch)
1428 {
1429   SilcClientConnection conn = fsm_context;
1430   SilcClient client = conn->client;
1431   SilcClientNotify notify = state_context;
1432   SilcNotifyPayload payload = notify->payload;
1433   SilcNotifyType type = silc_notify_get_type(payload);
1434   SilcArgumentPayload args = silc_notify_get_args(payload);
1435   SilcClientEntry client_entry = NULL;
1436   SilcNotifyType ntype = 0;
1437   SilcBool del_client = FALSE;
1438   unsigned char *pk, *tmp;
1439   SilcUInt32 mode, pk_len, tmp_len;
1440   SilcPublicKey public_key = NULL;
1441   SilcID id;
1442
1443   SILC_LOG_DEBUG(("Notify: WATCH"));
1444
1445   /* Get sender Client ID */
1446   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1447     goto out;
1448
1449   /* Find Client entry and if not found resolve it */
1450   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1451   if (!client_entry || !client_entry->nickname[0]) {
1452     /** Resolve client */
1453     silc_client_unref_client(client, conn, client_entry);
1454     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1455                                          client, conn, &id.u.client_id, NULL,
1456                                          silc_client_notify_resolved,
1457                                          notify));
1458     /* NOT REACHED */
1459   }
1460
1461   /* Get user mode */
1462   tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1463   if (!tmp || tmp_len != 4)
1464     goto out;
1465   SILC_GET32_MSB(mode, tmp);
1466
1467   /* Get notify type */
1468   tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1469   if (tmp && tmp_len != 2)
1470     goto out;
1471   if (tmp)
1472     SILC_GET16_MSB(ntype, tmp);
1473
1474   /* Get nickname */
1475   tmp = silc_argument_get_arg_type(args, 2, NULL);
1476   if (tmp) {
1477     char *tmp_nick = NULL;
1478
1479     if (client->internal->params->nickname_parse)
1480       client->internal->params->nickname_parse(client_entry->nickname,
1481                                                &tmp_nick);
1482     else
1483       tmp_nick = strdup(tmp);
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_del_client(client, conn, client_entry);
1521
1522   if (public_key)
1523     silc_pkcs_public_key_free(public_key);
1524
1525  out:
1526   /** Notify processed */
1527   silc_client_unref_client(client, conn, client_entry);
1528   silc_fsm_next(fsm, silc_client_notify_processed);
1529   return SILC_FSM_CONTINUE;
1530 }