More client library rewrites.
[silc.git] / lib / silcclient / client_notify.c
index d54e6ccc811e20919f1f9e5fda96fce1b64d3c79..206425dc9379d212964bc48a5a415d708450f415 100644 (file)
 
 #define NOTIFY conn->client->internal->ops->notify
 
+/* Notify processing context */
+typedef struct {
+  SilcPacket packet;
+  SilcNotifyPayload payload;
+  SilcFSMThread fsm;
+  SilcChannelEntry channel;
+} *SilcClientNotify;
+
 /************************ Static utility functions **************************/
 
 /* Entry resolving callback.  This will continue processing the notify. */
@@ -36,12 +44,40 @@ static void silc_client_notify_resolved(SilcClient client,
                                        SilcDList entries,
                                        void *context)
 {
+  SilcClientNotify notify = context;
+
   /* If no entries found, just finish the notify processing, a silent error */
   if (!entries)
-    silc_fsm_next(context, silc_client_notify_processed);
+    silc_fsm_next(notify->fsm, silc_client_notify_processed);
+
+  if (notify->channel) {
+    notify->channel->internal.resolve_cmd_ident = 0;
+    silc_client_unref_channel(client, conn, notify->channel);
+  }
 
   /* Continue processing the notify */
-  SILC_FSM_CALL_CONTINUE_SYNC(context);
+  SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm);
+}
+
+/* Continue notify processing after it was suspended while waiting for
+   channel information being resolved. */
+
+static SilcBool silc_client_notify_wait_continue(SilcClient client,
+                                                SilcClientConnection conn,
+                                                SilcCommand command,
+                                                SilcStatus status,
+                                                SilcStatus error,
+                                                void *context,
+                                                va_list ap)
+{
+  SilcClientNotify notify = context;
+
+  /* Continue after last command reply received */
+  if (SILC_STATUS_IS_ERROR(status) || status == SILC_STATUS_OK ||
+      status == SILC_STATUS_LIST_END)
+    SILC_FSM_CALL_CONTINUE(notify->fsm);
+
+  return TRUE;
 }
 
 /********************************* Notify ***********************************/
@@ -51,6 +87,7 @@ static void silc_client_notify_resolved(SilcClient client,
 SILC_FSM_STATE(silc_client_notify)
 {
   SilcPacket packet = state_context;
+  SilcClientNotify notify;
   SilcNotifyPayload payload;
 
   payload = silc_notify_payload_parse(silc_buffer_data(&packet->buffer),
@@ -68,8 +105,18 @@ SILC_FSM_STATE(silc_client_notify)
     return SILC_FSM_FINISH;
   }
 
+  notify = silc_calloc(1, sizeof(*notify));
+  if (!notify) {
+    silc_notify_payload_free(payload);
+    silc_packet_free(packet);
+    return SILC_FSM_FINISH;
+  }
+
   /* Save notify payload to packet context during processing */
-  packet->next = (void *)payload;
+  notify->packet = packet;
+  notify->payload = payload;
+  notify->fsm = fsm;
+  silc_fsm_set_state_context(fsm, notify);
 
   /* Process the notify */
   switch (silc_notify_get_type(payload)) {
@@ -158,6 +205,7 @@ SILC_FSM_STATE(silc_client_notify)
     /** Unknown notify */
     silc_notify_payload_free(payload);
     silc_packet_free(packet);
+    silc_free(notify);
     return SILC_FSM_FINISH;
     break;
   }
@@ -169,10 +217,13 @@ SILC_FSM_STATE(silc_client_notify)
 
 SILC_FSM_STATE(silc_client_notify_processed)
 {
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcPacket packet = notify->packet;
+  SilcNotifyPayload payload = notify->payload;
+
   silc_notify_payload_free(payload);
   silc_packet_free(packet);
+  silc_free(notify);
   return SILC_FSM_FINISH;
 }
 
@@ -182,8 +233,8 @@ SILC_FSM_STATE(silc_client_notify_none)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
 
@@ -203,8 +254,8 @@ SILC_FSM_STATE(silc_client_notify_invite)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry;
@@ -227,6 +278,17 @@ SILC_FSM_STATE(silc_client_notify_invite)
   /* Get the channel entry */
   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
 
+  /* If channel is being resolved handle notify after resolving */
+  if (channel->internal.resolve_cmd_ident) {
+    silc_client_unref_channel(client, conn, channel);
+    SILC_FSM_CALL(silc_client_command_pending(
+                                     conn, SILC_COMMAND_NONE,
+                                     channel->internal.resolve_cmd_ident,
+                                     silc_client_notify_wait_continue,
+                                     notify));
+    /* NOT REACHED */
+  }
+
   /* Get sender Client ID */
   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
@@ -236,10 +298,12 @@ SILC_FSM_STATE(silc_client_notify_invite)
   if (!client_entry || !client_entry->nickname[0]) {
     /** Resolve client */
     silc_client_unref_client(client, conn, client_entry);
-    SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
+    notify->channel = channel;
+    SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+                 silc_client_get_client_by_id_resolve(
                                         client, conn, &id.u.client_id, NULL,
                                         silc_client_notify_resolved,
-                                        fsm));
+                                        notify));
     /* NOT REACHED */
   }
 
@@ -263,8 +327,8 @@ SILC_FSM_STATE(silc_client_notify_join)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry;
@@ -282,6 +346,17 @@ SILC_FSM_STATE(silc_client_notify_join)
   if (!channel)
     goto out;
 
+  /* If channel is being resolved handle notify after resolving */
+  if (channel->internal.resolve_cmd_ident) {
+    silc_client_unref_channel(client, conn, channel);
+    SILC_FSM_CALL(silc_client_command_pending(
+                                     conn, SILC_COMMAND_NONE,
+                                     channel->internal.resolve_cmd_ident,
+                                     silc_client_notify_wait_continue,
+                                     notify));
+    /* NOT REACHED */
+  }
+
   /* Get Client ID */
   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
@@ -292,10 +367,12 @@ SILC_FSM_STATE(silc_client_notify_join)
       !client_entry->username[0]) {
     /** Resolve client */
     silc_client_unref_client(client, conn, client_entry);
-    SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
+    notify->channel = channel;
+    SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+                 silc_client_get_client_by_id_resolve(
                                         client, conn, &id.u.client_id, NULL,
                                         silc_client_notify_resolved,
-                                        fsm));
+                                        notify));
     /* NOT REACHED */
   }
 
@@ -303,7 +380,8 @@ SILC_FSM_STATE(silc_client_notify_join)
     silc_client_nickname_format(client, conn, client_entry);
 
   /* Join the client to channel */
-  silc_client_add_to_channel(channel, client_entry, 0);
+  if (!silc_client_add_to_channel(channel, client_entry, 0))
+    goto out;
 
   /* Notify application. */
   NOTIFY(client, conn, type, client_entry, channel);
@@ -325,8 +403,9 @@ SILC_FSM_STATE(silc_client_notify_leave)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
+  SilcPacket packet = notify->packet;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry = NULL;
@@ -344,6 +423,17 @@ SILC_FSM_STATE(silc_client_notify_leave)
   if (!channel)
     goto out;
 
+  /* If channel is being resolved handle notify after resolving */
+  if (channel->internal.resolve_cmd_ident) {
+    silc_client_unref_channel(client, conn, channel);
+    SILC_FSM_CALL(silc_client_command_pending(
+                                     conn, SILC_COMMAND_NONE,
+                                     channel->internal.resolve_cmd_ident,
+                                     silc_client_notify_wait_continue,
+                                     notify));
+    /* NOT REACHED */
+  }
+
   /* Get Client ID */
   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
@@ -399,8 +489,8 @@ SILC_FSM_STATE(silc_client_notify_signoff)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry;
@@ -453,8 +543,9 @@ SILC_FSM_STATE(silc_client_notify_topic_set)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
+  SilcPacket packet = notify->packet;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry = NULL;
@@ -475,6 +566,17 @@ SILC_FSM_STATE(silc_client_notify_topic_set)
   if (!channel)
     goto out;
 
+  /* If channel is being resolved handle notify after resolving */
+  if (channel->internal.resolve_cmd_ident) {
+    silc_client_unref_channel(client, conn, channel);
+    SILC_FSM_CALL(silc_client_command_pending(
+                                     conn, SILC_COMMAND_NONE,
+                                     channel->internal.resolve_cmd_ident,
+                                     silc_client_notify_wait_continue,
+                                     notify));
+    /* NOT REACHED */
+  }
+
   /* Get ID */
   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
@@ -490,10 +592,12 @@ SILC_FSM_STATE(silc_client_notify_topic_set)
     if (!client_entry || !client_entry->nickname[0]) {
       /** Resolve client */
       silc_client_unref_client(client, conn, client_entry);
-      SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
+      notify->channel = channel;
+      SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+                   silc_client_get_client_by_id_resolve(
                                           client, conn, &id.u.client_id, NULL,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = client_entry;
@@ -502,10 +606,12 @@ SILC_FSM_STATE(silc_client_notify_topic_set)
     server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
     if (!server) {
       /** Resolve server */
-      SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
+      notify->channel = channel;
+      SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+                   silc_client_get_server_by_id_resolve(
                                           client, conn, &id.u.server_id,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = server;
@@ -515,10 +621,12 @@ SILC_FSM_STATE(silc_client_notify_topic_set)
                                                  &id.u.channel_id);
     if (!channel_entry) {
       /** Resolve channel */
-      SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
+      notify->channel = channel;
+      SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+                   silc_client_get_channel_by_id_resolve(
                                    client, conn, &id.u.channel_id,
                                    silc_client_notify_resolved,
-                                   fsm));
+                                   notify));
       /* NOT REACHED */
     }
     entry = channel_entry;
@@ -552,14 +660,14 @@ SILC_FSM_STATE(silc_client_notify_nick_change)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry = NULL;
   unsigned char *tmp, *nick, oldnick[128 + 1];
   SilcUInt32 tmp_len;
-  SilcID id;
+  SilcID id, id2;
 
   SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
 
@@ -572,6 +680,15 @@ SILC_FSM_STATE(silc_client_notify_nick_change)
       SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
     goto out;
 
+  /* Get new Client ID */
+  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
+    goto out;
+
+  /* Ignore my ID */
+  if (conn->local_id &&
+      SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
+    goto out;
+
   /* Find old Client entry */
   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
   if (!client_entry || !client_entry->nickname[0]) {
@@ -580,14 +697,10 @@ SILC_FSM_STATE(silc_client_notify_nick_change)
     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
                                         client, conn, &id.u.client_id, NULL,
                                         silc_client_notify_resolved,
-                                        fsm));
+                                        notify));
     /* NOT REACHED */
   }
 
-  /* Get new Client ID */
-  if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
-    goto out;
-
   /* Take the new nickname */
   tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
   if (!tmp)
@@ -596,12 +709,13 @@ SILC_FSM_STATE(silc_client_notify_nick_change)
   /* Check whether nickname changed at all.  It is possible that nick
      change notify is received but nickname didn't change, only the
      ID changes.  If Client ID hash match, nickname didn't change. */
-  if (SILC_ID_COMPARE_HASH(&client_entry->id, &id.u.client_id) &&
+  if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
       silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
     /* Nickname didn't change.  Update only Client ID.  We don't notify
        application because nickname didn't change. */
     silc_idcache_update(conn->internal->client_cache, client_entry,
-                       &client_entry->id, &id.u.client_id, NULL, NULL, FALSE);
+                       &client_entry->id, &id2.u.client_id, NULL,
+                       NULL, FALSE);
     goto out;
   }
 
@@ -640,8 +754,9 @@ SILC_FSM_STATE(silc_client_notify_cmode_change)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
+  SilcPacket packet = notify->packet;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry = NULL;
@@ -665,6 +780,17 @@ SILC_FSM_STATE(silc_client_notify_cmode_change)
   if (!channel)
     goto out;
 
+  /* If channel is being resolved handle notify after resolving */
+  if (channel->internal.resolve_cmd_ident) {
+    silc_client_unref_channel(client, conn, channel);
+    SILC_FSM_CALL(silc_client_command_pending(
+                                     conn, SILC_COMMAND_NONE,
+                                     channel->internal.resolve_cmd_ident,
+                                     silc_client_notify_wait_continue,
+                                     notify));
+    /* NOT REACHED */
+  }
+
   /* Get the mode */
   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
   if (!tmp)
@@ -681,10 +807,12 @@ SILC_FSM_STATE(silc_client_notify_cmode_change)
     if (!client_entry || !client_entry->nickname[0]) {
       /** Resolve client */
       silc_client_unref_client(client, conn, client_entry);
-      SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
+      notify->channel = channel;
+      SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+                   silc_client_get_client_by_id_resolve(
                                           client, conn, &id.u.client_id, NULL,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = client_entry;
@@ -693,10 +821,12 @@ SILC_FSM_STATE(silc_client_notify_cmode_change)
     server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
     if (!server) {
       /** Resolve server */
-      SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
+      notify->channel = channel;
+      SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+                   silc_client_get_server_by_id_resolve(
                                           client, conn, &id.u.server_id,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = server;
@@ -706,10 +836,12 @@ SILC_FSM_STATE(silc_client_notify_cmode_change)
                                                  &id.u.channel_id);
     if (!channel_entry) {
       /** Resolve channel */
-      SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
+      notify->channel = channel;
+      SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+                   silc_client_get_channel_by_id_resolve(
                                    client, conn, &id.u.channel_id,
                                    silc_client_notify_resolved,
-                                   fsm));
+                                   notify));
       /* NOT REACHED */
     }
     entry = channel_entry;
@@ -800,8 +932,9 @@ SILC_FSM_STATE(silc_client_notify_cumode_change)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
+  SilcPacket packet = notify->packet;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry = NULL, client_entry2 = NULL;
@@ -823,6 +956,17 @@ SILC_FSM_STATE(silc_client_notify_cumode_change)
   if (!channel)
     goto out;
 
+  /* If channel is being resolved handle notify after resolving */
+  if (channel->internal.resolve_cmd_ident) {
+    silc_client_unref_channel(client, conn, channel);
+    SILC_FSM_CALL(silc_client_command_pending(
+                                     conn, SILC_COMMAND_NONE,
+                                     channel->internal.resolve_cmd_ident,
+                                     silc_client_notify_wait_continue,
+                                     notify));
+    /* NOT REACHED */
+  }
+
   /* Get the mode */
   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
   if (!tmp)
@@ -839,10 +983,12 @@ SILC_FSM_STATE(silc_client_notify_cumode_change)
     if (!client_entry || !client_entry->nickname[0]) {
       /** Resolve client */
       silc_client_unref_client(client, conn, client_entry);
-      SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
+      notify->channel = channel;
+      SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+                   silc_client_get_client_by_id_resolve(
                                           client, conn, &id.u.client_id, NULL,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = client_entry;
@@ -851,10 +997,12 @@ SILC_FSM_STATE(silc_client_notify_cumode_change)
     server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
     if (!server) {
       /** Resolve server */
-      SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
+      notify->channel = channel;
+      SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+                   silc_client_get_server_by_id_resolve(
                                           client, conn, &id.u.server_id,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = server;
@@ -864,10 +1012,12 @@ SILC_FSM_STATE(silc_client_notify_cumode_change)
                                                  &id.u.channel_id);
     if (!channel_entry) {
       /** Resolve channel */
-      SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
+      notify->channel = channel;
+      SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+                   silc_client_get_channel_by_id_resolve(
                                    client, conn, &id.u.channel_id,
                                    silc_client_notify_resolved,
-                                   fsm));
+                                   notify));
       /* NOT REACHED */
     }
     entry = channel_entry;
@@ -886,7 +1036,7 @@ SILC_FSM_STATE(silc_client_notify_cumode_change)
     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
                                         client, conn, &id2.u.client_id, NULL,
                                         silc_client_notify_resolved,
-                                        fsm));
+                                        notify));
     /* NOT REACHED */
   }
 
@@ -921,8 +1071,8 @@ SILC_FSM_STATE(silc_client_notify_motd)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   unsigned char *tmp;
@@ -952,8 +1102,8 @@ SILC_FSM_STATE(silc_client_notify_channel_change)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcChannelEntry channel = NULL;
@@ -970,6 +1120,17 @@ SILC_FSM_STATE(silc_client_notify_channel_change)
   if (!channel)
     goto out;
 
+  /* If channel is being resolved handle notify after resolving */
+  if (channel->internal.resolve_cmd_ident) {
+    silc_client_unref_channel(client, conn, channel);
+    SILC_FSM_CALL(silc_client_command_pending(
+                                     conn, SILC_COMMAND_NONE,
+                                     channel->internal.resolve_cmd_ident,
+                                     silc_client_notify_wait_continue,
+                                     notify));
+    /* NOT REACHED */
+  }
+
   /* Get the new ID */
   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
@@ -996,8 +1157,9 @@ SILC_FSM_STATE(silc_client_notify_kicked)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
+  SilcPacket packet = notify->packet;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry, client_entry2;
@@ -1009,6 +1171,25 @@ SILC_FSM_STATE(silc_client_notify_kicked)
 
   SILC_LOG_DEBUG(("Notify: KICKED"));
 
+  /* Get channel entry */
+  if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
+                     &id.u.channel_id, sizeof(id.u.channel_id)))
+    goto out;
+  channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
+  if (!channel)
+    goto out;
+
+  /* If channel is being resolved handle notify after resolving */
+  if (channel->internal.resolve_cmd_ident) {
+    silc_client_unref_channel(client, conn, channel);
+    SILC_FSM_CALL(silc_client_command_pending(
+                                     conn, SILC_COMMAND_NONE,
+                                     channel->internal.resolve_cmd_ident,
+                                     silc_client_notify_wait_continue,
+                                     notify));
+    /* NOT REACHED */
+  }
+
   /* Get Client ID */
   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
@@ -1018,14 +1199,6 @@ SILC_FSM_STATE(silc_client_notify_kicked)
   if (!client_entry)
     goto out;
 
-  /* Get channel entry */
-  if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
-                     &id.u.channel_id, sizeof(id.u.channel_id)))
-    goto out;
-  channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
-  if (!channel)
-    goto out;
-
   /* Get kicker's Client ID */
   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
     goto out;
@@ -1036,10 +1209,12 @@ SILC_FSM_STATE(silc_client_notify_kicked)
     /** Resolve client */
     silc_client_unref_client(client, conn, client_entry);
     silc_client_unref_client(client, conn, client_entry2);
-    SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
+    notify->channel = channel;
+    SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+                 silc_client_get_client_by_id_resolve(
                                         client, conn, &id.u.client_id, NULL,
                                         silc_client_notify_resolved,
-                                        fsm));
+                                        notify));
     /* NOT REACHED */
   }
 
@@ -1084,8 +1259,8 @@ SILC_FSM_STATE(silc_client_notify_killed)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry = NULL, client_entry2 = NULL;
@@ -1125,7 +1300,7 @@ SILC_FSM_STATE(silc_client_notify_killed)
       SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
                                           client, conn, &id.u.client_id, NULL,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = client_entry2;
@@ -1137,7 +1312,7 @@ SILC_FSM_STATE(silc_client_notify_killed)
       SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
                                           client, conn, &id.u.server_id,
                                           silc_client_notify_resolved,
-                                          fsm));
+                                          notify));
       /* NOT REACHED */
     }
     entry = server;
@@ -1150,7 +1325,7 @@ SILC_FSM_STATE(silc_client_notify_killed)
       SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
                                    client, conn, &id.u.channel_id,
                                    silc_client_notify_resolved,
-                                   fsm));
+                                   notify));
       /* NOT REACHED */
     }
     entry = channel_entry;
@@ -1185,8 +1360,8 @@ SILC_FSM_STATE(silc_client_notify_server_signoff)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry;
@@ -1235,8 +1410,8 @@ SILC_FSM_STATE(silc_client_notify_error)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry;
@@ -1281,12 +1456,12 @@ SILC_FSM_STATE(silc_client_notify_watch)
 {
   SilcClientConnection conn = fsm_context;
   SilcClient client = conn->client;
-  SilcPacket packet = state_context;
-  SilcNotifyPayload payload = (SilcNotifyPayload)packet->next;
+  SilcClientNotify notify = state_context;
+  SilcNotifyPayload payload = notify->payload;
   SilcNotifyType type = silc_notify_get_type(payload);
   SilcArgumentPayload args = silc_notify_get_args(payload);
   SilcClientEntry client_entry = NULL;
-  SilcNotifyType notify = 0;
+  SilcNotifyType ntype = 0;
   SilcBool del_client = FALSE;
   unsigned char *pk, *tmp;
   SilcUInt32 mode, pk_len, tmp_len;
@@ -1307,7 +1482,7 @@ SILC_FSM_STATE(silc_client_notify_watch)
     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
                                         client, conn, &id.u.client_id, NULL,
                                         silc_client_notify_resolved,
-                                        fsm));
+                                        notify));
     /* NOT REACHED */
   }
 
@@ -1322,7 +1497,7 @@ SILC_FSM_STATE(silc_client_notify_watch)
   if (tmp && tmp_len != 2)
     goto out;
   if (tmp)
-    SILC_GET16_MSB(notify, tmp);
+    SILC_GET16_MSB(ntype, tmp);
 
   /* Get nickname */
   tmp = silc_argument_get_arg_type(args, 2, NULL);
@@ -1353,7 +1528,7 @@ SILC_FSM_STATE(silc_client_notify_watch)
   }
 
   /* Notify application. */
-  NOTIFY(client, conn, type, client_entry, tmp, mode, notify,
+  NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
         client_entry->public_key);
 
   client_entry->mode = mode;
@@ -1361,12 +1536,12 @@ SILC_FSM_STATE(silc_client_notify_watch)
   /* If nickname was changed, remove the client entry unless the
      client is on some channel */
   /* XXX, why do we need to remove the client entry?? */
-  if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
+  if (tmp && ntype == SILC_NOTIFY_TYPE_NICK_CHANGE &&
       !silc_hash_table_count(client_entry->channels))
     del_client = TRUE;
-  else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
-          notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
-          notify == SILC_NOTIFY_TYPE_KILLED)
+  else if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
+          ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
+          ntype == SILC_NOTIFY_TYPE_KILLED)
     del_client = TRUE;
 
   if (del_client)