SILC_FSM_* macro API changes.
[silc.git] / lib / silcclient / command.c
index de95e743720c1c22cfd3ad544a1b161a65a15402..32d436ac10ff55c8ff833084659223c6afdf08fe 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2006 Pekka Riikonen
+  Copyright (C) 1997 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -119,9 +119,6 @@ static void silc_client_command_resolve_continue(SilcClient client,
   if (status != SILC_STATUS_OK)
     silc_fsm_next(&cmd->thread, silc_client_command_continue_error);
 
-  if (clients)
-    silc_dlist_uninit(clients);
-
   /* Continue with the command */
   SILC_FSM_CALL_CONTINUE(&cmd->thread);
 }
@@ -139,11 +136,17 @@ silc_client_command_register(SilcClient client,
   SilcClientCommand cmd;
 
   cmd = silc_calloc(1, sizeof(*cmd));
+  if (!cmd)
+    return FALSE;
   cmd->cmd = command;
   cmd->command = command_func;
   cmd->reply = command_reply_func;
-  cmd->name = name ? strdup(name) : NULL;
   cmd->max_args = max_args;
+  cmd->name = name ? strdup(name) : NULL;
+  if (!cmd->name) {
+    silc_free(cmd);
+    return FALSE;
+  }
 
   silc_list_add(client->internal->commands, cmd);
 
@@ -191,27 +194,20 @@ static SilcClientCommand silc_client_command_find(SilcClient client,
   return NULL;
 }
 
-/* Free command context and its internals */
-
-static void silc_client_command_free(SilcClientCommandContext cmd)
-{
-  int i;
-
-  for (i = 0; i < cmd->argc; i++)
-    silc_free(cmd->argv[i]);
-  silc_free(cmd->argv);
-  silc_free(cmd->argv_lens);
-  silc_free(cmd->argv_types);
-  silc_free(cmd);
-}
-
 /* Command thread destructor */
 
 static void silc_client_command_destructor(SilcFSMThread thread,
                                           void *fsm_context,
                                           void *destructor_context)
 {
-  silc_client_command_free(fsm_context);
+  SilcClientCommandContext cmd = fsm_context;
+  SilcClientConnection conn = cmd->conn;
+
+  /* Removes commands that aren't waiting for reply but are waiting
+     for something.  They may not have been removed yet. */
+  silc_list_del(conn->internal->pending_commands, cmd);
+
+  silc_client_command_free(cmd);
 }
 
 /* Add a command pending a command reply.  Used internally by the library. */
@@ -262,6 +258,9 @@ static SilcUInt16 silc_client_command_send_vap(SilcClient client,
 
   SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
 
+  if (conn->internal->disconnected)
+    return 0;
+
   if (!cmd->cmd_ident)
     cmd->cmd_ident = silc_client_cmd_ident(conn);
 
@@ -305,6 +304,9 @@ silc_client_command_send_arg_array(SilcClient client,
 
   SILC_LOG_DEBUG(("Send command %s", silc_get_command_name(command)));
 
+  if (conn->internal->disconnected)
+    return 0;
+
   if (!cmd->cmd_ident)
     cmd->cmd_ident = silc_client_cmd_ident(conn);
 
@@ -353,6 +355,26 @@ static SilcUInt16 silc_client_command_send_va(SilcClientConnection conn,
 
 /****************************** Command API *********************************/
 
+/* Free command context and its internals */
+
+void silc_client_command_free(SilcClientCommandContext cmd)
+{
+  SilcClientCommandReplyCallback cb;
+  int i;
+
+  for (i = 0; i < cmd->argc; i++)
+    silc_free(cmd->argv[i]);
+  silc_free(cmd->argv);
+  silc_free(cmd->argv_lens);
+  silc_free(cmd->argv_types);
+
+  silc_list_start(cmd->reply_callbacks);
+  while ((cb = silc_list_get(cmd->reply_callbacks)))
+    silc_free(cb);
+
+  silc_free(cmd);
+}
+
 /* Executes a command */
 
 SilcUInt16 silc_client_command_call(SilcClient client,
@@ -410,10 +432,10 @@ SilcUInt16 silc_client_command_call(SilcClient client,
       argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
       argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
       if (!argv || !argv_lens || !argv_types)
-       return FALSE;
+       return 0;
       argv[argc] = silc_memdup(arg, strlen(arg));
       if (!argv[argc])
-       return FALSE;
+       return 0;
       argv_lens[argc] = strlen(arg);
       argv_types[argc] = argc;
       argc++;
@@ -435,6 +457,8 @@ SilcUInt16 silc_client_command_call(SilcClient client,
   cmd->cmd_ident = silc_client_cmd_ident(conn);
   cmd->called = TRUE;
   cmd->verbose = TRUE;
+  silc_list_init(cmd->reply_callbacks,
+                struct SilcClientCommandReplyCallbackStruct, next);
 
   /*** Call command */
   SILC_LOG_DEBUG(("Calling %s command", silc_get_command_name(cmd->cmd)));
@@ -467,6 +491,8 @@ SilcUInt16 silc_client_command_send(SilcClient client,
     return 0;
   cmd->conn = conn;
   cmd->cmd = command;
+  silc_list_init(cmd->reply_callbacks,
+                struct SilcClientCommandReplyCallbackStruct, next);
 
   /* Send the command */
   va_start(ap, argc);
@@ -567,7 +593,7 @@ SilcBool silc_client_command_pending(SilcClientConnection conn,
 
   silc_mutex_unlock(conn->internal->lock);
 
-  return FALSE;
+  return TRUE;
 }
 
 /******************************** WHOIS *************************************/
@@ -588,18 +614,24 @@ SILC_FSM_STATE(silc_client_command_whois)
 
   /* Given without arguments fetches client's own information */
   if (cmd->argc < 2) {
-    silc_client_command_send(conn->client, conn, SILC_COMMAND_WHOIS,
-                            NULL, NULL, 1,
-                            4, silc_buffer_datalen(conn->local_idp));
-    goto out;
+    silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1, 4,
+                               silc_buffer_data(conn->internal->local_idp),
+                               silc_buffer_len(conn->internal->local_idp));
+
+    /* Notify application */
+    COMMAND(SILC_STATUS_OK);
+
+    /** Wait for command reply */
+    silc_fsm_next(fsm, silc_client_command_reply_wait);
+    return SILC_FSM_CONTINUE;
   }
 
   for (i = 1; i < cmd->argc; i++) {
     if (!strcasecmp(cmd->argv[i], "-details")) {
-       details = TRUE;
+      details = TRUE;
     } else if (!strcasecmp(cmd->argv[i], "-pubkey") && cmd->argc > i + 1) {
-       pubkey = cmd->argv[i + 1];
-       i++;
+      pubkey = cmd->argv[i + 1];
+      i++;
     } else {
       /* We assume that the first parameter is the nickname, if it isn't
          -details or -pubkey. The last parameter should always be the count */
@@ -819,14 +851,15 @@ SILC_FSM_STATE(silc_client_command_list)
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
-  SilcChannelEntry channel;
+  SilcClient client = conn->client;
+  SilcChannelEntry channel = NULL;
   SilcBuffer idp = NULL;
 
   if (cmd->argc == 2) {
     /* Get the Channel ID of the channel */
     channel = silc_client_get_channel(conn->client, cmd->conn, cmd->argv[1]);
     if (channel)
-      idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+      idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
   }
 
   if (!idp)
@@ -836,6 +869,7 @@ SILC_FSM_STATE(silc_client_command_list)
                                1, 1, silc_buffer_datalen(idp));
 
   silc_buffer_free(idp);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
@@ -853,6 +887,7 @@ SILC_FSM_STATE(silc_client_command_topic)
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
+  SilcClient client = conn->client;
   SilcChannelEntry channel;
   SilcBuffer idp;
   char *name;
@@ -887,7 +922,7 @@ SILC_FSM_STATE(silc_client_command_topic)
     goto out;
   }
 
-  idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
 
   /* Send TOPIC command to the server */
   if (cmd->argc > 2)
@@ -899,6 +934,7 @@ SILC_FSM_STATE(silc_client_command_topic)
                                1, silc_buffer_datalen(idp));
 
   silc_buffer_free(idp);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
@@ -922,7 +958,7 @@ SILC_FSM_STATE(silc_client_command_invite)
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
   SilcClientEntry client_entry = NULL;
-  SilcChannelEntry channel;
+  SilcChannelEntry channel = NULL;
   SilcBuffer clidp, chidp, args = NULL;
   SilcPublicKey pubkey = NULL;
   SilcDList clients = NULL;
@@ -945,6 +981,7 @@ SILC_FSM_STATE(silc_client_command_invite)
     }
 
     channel = conn->current_channel;
+    silc_client_ref_channel(client, conn, channel);
   } else {
     name = cmd->argv[1];
 
@@ -958,10 +995,7 @@ SILC_FSM_STATE(silc_client_command_invite)
   /* Parse the typed nickname. */
   if (cmd->argc == 3) {
     if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
-      if (client->internal->params->nickname_parse)
-       client->internal->params->nickname_parse(cmd->argv[2], &nickname);
-      else
-       nickname = strdup(cmd->argv[2]);
+      silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
 
       /* Find client entry */
       clients = silc_client_get_clients_local(client, conn, nickname,
@@ -1006,7 +1040,7 @@ SILC_FSM_STATE(silc_client_command_invite)
   }
 
   /* Send the command */
-  chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
   if (client_entry) {
     clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
     silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 4,
@@ -1026,6 +1060,7 @@ SILC_FSM_STATE(silc_client_command_invite)
   silc_buffer_free(args);
   silc_free(nickname);
   silc_client_list_free(client, conn, clients);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
@@ -1049,13 +1084,22 @@ SILC_FSM_STATE(silc_client_command_quit_final)
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
 
+  SILC_LOG_DEBUG(("Quitting"));
+
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
-  /* Close connection */
-  conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED,
-                conn->context);
-  //  silc_client_close_connection(q->client, q->conn->sock->user_data);
+  /* Call connection callback */
+  if (!conn->internal->callback_called)
+    conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED,
+                  0, NULL, conn->callback_context);
+  conn->internal->callback_called = TRUE;
+
+  /* Signal to close connection */
+  if (!conn->internal->disconnected) {
+    conn->internal->disconnected = TRUE;
+    SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
+  }
 
   return SILC_FSM_FINISH;
 }
@@ -1105,11 +1149,7 @@ SILC_FSM_STATE(silc_client_command_kill)
   }
 
   /* Parse the typed nickname. */
-  if (client->internal->params->nickname_parse)
-    client->internal->params->nickname_parse(cmd->argv[1], &nickname);
-  else
-    nickname = strdup(cmd->argv[1]);
-  if (!nickname)
+  if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname))
     return SILC_FSM_FINISH;
 
   /* Get the target client */
@@ -1134,7 +1174,7 @@ SILC_FSM_STATE(silc_client_command_kill)
       auth = silc_auth_public_key_auth_generate(conn->public_key,
                                                conn->private_key,
                                                conn->client->rng,
-                                               client->sha1hash,
+                                               conn->internal->sha1hash,
                                                &target->id, SILC_ID_CLIENT);
     }
   }
@@ -1192,14 +1232,10 @@ SILC_FSM_STATE(silc_client_command_stats)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
 
-  if (cmd->argc < 2) {
-    COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    return SILC_FSM_FINISH;
-  }
-
   /* Send the command */
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
-                             1, silc_buffer_datalen(conn->remote_idp));
+                             1, silc_buffer_datalen(conn->internal->
+                                                    remote_idp));
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
@@ -1225,7 +1261,8 @@ SILC_FSM_STATE(silc_client_command_ping)
 
   /* Send the command */
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
-                             1, silc_buffer_datalen(conn->remote_idp));
+                             1, silc_buffer_datalen(conn->internal->
+                                                    remote_idp));
 
   /* Save ping time */
   cmd->context = SILC_64_TO_PTR(silc_time());
@@ -1246,7 +1283,8 @@ SILC_FSM_STATE(silc_client_command_join)
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
-  SilcChannelEntry channel;
+  SilcClient client = conn->client;
+  SilcChannelEntry channel = NULL;
   SilcBuffer auth = NULL, cauth = NULL;
   char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
   int i, passphrase_len = 0;
@@ -1275,7 +1313,7 @@ SILC_FSM_STATE(silc_client_command_join)
       auth = silc_auth_public_key_auth_generate(conn->public_key,
                                                conn->private_key,
                                                conn->client->rng,
-                                               conn->client->sha1hash,
+                                               conn->internal->sha1hash,
                                                conn->local_id,
                                                SILC_ID_CLIENT);
     } else if (!strcasecmp(cmd->argv[i], "-auth")) {
@@ -1301,13 +1339,13 @@ SILC_FSM_STATE(silc_client_command_join)
       }
 
       pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
-      silc_hash_make(conn->client->sha1hash, pk, pk_len, pkhash);
+      silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash);
       silc_free(pk);
       pubdata = silc_rng_get_rn_data(conn->client->rng, 128);
       memcpy(pubdata, pkhash, 20);
       cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
                                                      pubdata, 128,
-                                                     conn->client->sha1hash,
+                                                     conn->internal->sha1hash,
                                                      conn->local_id,
                                                      SILC_ID_CLIENT);
       memset(pubdata, 0, 128);
@@ -1331,7 +1369,8 @@ SILC_FSM_STATE(silc_client_command_join)
   /* Send JOIN command to the server */
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7,
                              1, name, strlen(name),
-                             2, silc_buffer_datalen(conn->local_idp),
+                             2, silc_buffer_datalen(conn->internal->
+                                                    local_idp),
                              3, passphrase, passphrase_len,
                              4, cipher, cipher ? strlen(cipher) : 0,
                              5, hmac, hmac ? strlen(hmac) : 0,
@@ -1343,6 +1382,7 @@ SILC_FSM_STATE(silc_client_command_join)
   if (passphrase)
     memset(passphrase, 0, strlen(passphrase));
   silc_free(passphrase);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
@@ -1352,6 +1392,7 @@ SILC_FSM_STATE(silc_client_command_join)
   return SILC_FSM_CONTINUE;
 
  out:
+  silc_client_unref_channel(client, conn, channel);
   return SILC_FSM_FINISH;
 }
 
@@ -1516,7 +1557,8 @@ SILC_FSM_STATE(silc_client_command_umode)
 
   /* Send the command */
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
-                             1, silc_buffer_datalen(conn->local_idp),
+                             1, silc_buffer_datalen(conn->internal->
+                                                    local_idp),
                              2, modebuf, sizeof(modebuf));
 
   /* Notify application */
@@ -1538,7 +1580,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
-  SilcChannelEntry channel;
+  SilcChannelEntry channel = NULL;
   SilcBuffer chidp, auth = NULL, pk = NULL;
   unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
   SilcUInt32 mode, add, type, len, arg_len = 0;
@@ -1558,6 +1600,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
     }
 
     channel = conn->current_channel;
+    silc_client_ref_channel(client, conn, channel);
   } else {
     name = cmd->argv[1];
 
@@ -1717,7 +1760,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
        pk = silc_public_key_payload_encode(pubkey);
        auth = silc_auth_public_key_auth_generate(pubkey, privkey,
                                                  conn->client->rng,
-                                                 conn->client->sha1hash,
+                                                 conn->internal->sha1hash,
                                                  conn->local_id,
                                                  SILC_ID_CLIENT);
        arg = silc_buffer_data(auth);
@@ -1737,7 +1780,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
 
        if (cmd->argc == 3) {
          /* Send empty command to receive the public key list. */
-         chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+         chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
          silc_client_command_send_va(conn, cmd, SILC_COMMAND_CMODE,
                                      NULL, NULL, 1,
                                      1, silc_buffer_datalen(chidp));
@@ -1791,7 +1834,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
     }
   }
 
-  chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
   SILC_PUT32_MSB(mode, modebuf);
 
   /* Send the command. We support sending only one mode at once that
@@ -1811,6 +1854,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
   silc_buffer_free(chidp);
   silc_buffer_free(auth);
   silc_buffer_free(pk);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
@@ -1820,6 +1864,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
   return SILC_FSM_CONTINUE;
 
  out:
+  silc_client_unref_channel(client, conn, channel);
   return SILC_FSM_FINISH;
 }
 
@@ -1832,7 +1877,7 @@ SILC_FSM_STATE(silc_client_command_cumode)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
-  SilcChannelEntry channel;
+  SilcChannelEntry channel = NULL;
   SilcChannelUser chu;
   SilcClientEntry client_entry;
   SilcBuffer clidp, chidp, auth = NULL;
@@ -1856,6 +1901,7 @@ SILC_FSM_STATE(silc_client_command_cumode)
     }
 
     channel = conn->current_channel;
+    silc_client_ref_channel(client, conn, channel);
   } else {
     name = cmd->argv[1];
 
@@ -1867,10 +1913,7 @@ SILC_FSM_STATE(silc_client_command_cumode)
   }
 
   /* Parse the typed nickname. */
-  if (client->internal->params->nickname_parse)
-    client->internal->params->nickname_parse(cmd->argv[3], &nickname);
-  else
-    nickname = strdup(cmd->argv[3]);
+  silc_client_nickname_parse(client, conn, cmd->argv[3], &nickname);
 
   /* Find client entry */
   clients = silc_client_get_clients_local(client, conn, nickname,
@@ -1930,7 +1973,7 @@ SILC_FSM_STATE(silc_client_command_cumode)
 
        auth = silc_auth_public_key_auth_generate(pubkey, privkey,
                                                  conn->client->rng,
-                                                 conn->client->sha1hash,
+                                                 conn->internal->sha1hash,
                                                  conn->local_id,
                                                  SILC_ID_CLIENT);
        mode |= SILC_CHANNEL_UMODE_CHANFO;
@@ -1975,7 +2018,7 @@ SILC_FSM_STATE(silc_client_command_cumode)
     }
   }
 
-  chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
   SILC_PUT32_MSB(mode, modebuf);
   clidp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
 
@@ -1991,11 +2034,19 @@ SILC_FSM_STATE(silc_client_command_cumode)
   silc_buffer_free(clidp);
   if (auth)
     silc_buffer_free(auth);
+  silc_free(nickname);
+  silc_client_list_free(client, conn, clients);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
+  /** Wait for command reply */
+  silc_fsm_next(fsm, silc_client_command_reply_wait);
+  return SILC_FSM_CONTINUE;
+
  out:
+  silc_client_unref_channel(client, conn, channel);
   silc_client_list_free(client, conn, clients);
   silc_free(nickname);
   return SILC_FSM_FINISH;
@@ -2010,7 +2061,7 @@ SILC_FSM_STATE(silc_client_command_kick)
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
-  SilcChannelEntry channel;
+  SilcChannelEntry channel = NULL;
   SilcBuffer idp, idp2;
   SilcClientEntry target;
   SilcDList clients = NULL;
@@ -2047,10 +2098,7 @@ SILC_FSM_STATE(silc_client_command_kick)
   }
 
   /* Parse the typed nickname. */
-  if (client->internal->params->nickname_parse)
-    client->internal->params->nickname_parse(cmd->argv[2], &nickname);
-  else
-    nickname = strdup(cmd->argv[2]);
+  silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname);
 
   /* Get the target client */
   clients = silc_client_get_clients_local(client, conn, nickname,
@@ -2064,7 +2112,7 @@ SILC_FSM_STATE(silc_client_command_kick)
   target = silc_dlist_get(clients);
 
   /* Send KICK command to the server */
-  idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
   idp2 = silc_id_payload_encode(&target->id, SILC_ID_CLIENT);
   if (cmd->argc == 3)
     silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
@@ -2080,6 +2128,7 @@ SILC_FSM_STATE(silc_client_command_kick)
   silc_buffer_free(idp2);
   silc_free(nickname);
   silc_client_list_free(client, conn, clients);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
@@ -2089,6 +2138,7 @@ SILC_FSM_STATE(silc_client_command_kick)
   return SILC_FSM_CONTINUE;
 
  out:
+  silc_client_unref_channel(client, conn, channel);
   silc_free(nickname);
   return SILC_FSM_FINISH;
 }
@@ -2226,6 +2276,7 @@ SILC_FSM_STATE(silc_client_command_ban)
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
+  SilcClient client = conn->client;
   SilcChannelEntry channel;
   SilcBuffer chidp, args = NULL;
   char *name, *ban = NULL;
@@ -2247,6 +2298,7 @@ SILC_FSM_STATE(silc_client_command_ban)
     }
 
     channel = conn->current_channel;
+    silc_client_ref_channel(client, conn, channel);
   } else {
     name = cmd->argv[1];
 
@@ -2286,7 +2338,7 @@ SILC_FSM_STATE(silc_client_command_ban)
     }
   }
 
-  chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  chidp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
 
   /* Send the command */
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 3,
@@ -2296,6 +2348,7 @@ SILC_FSM_STATE(silc_client_command_ban)
 
   silc_buffer_free(chidp);
   silc_buffer_free(args);
+  silc_client_unref_channel(client, conn, channel);
 
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
@@ -2383,7 +2436,8 @@ SILC_FSM_STATE(silc_client_command_watch)
 
   /* Send the commmand */
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
-                             1, silc_buffer_datalen(conn->local_idp),
+                             1, silc_buffer_datalen(conn->internal->
+                                                    local_idp),
                              type, pubkey ? args->data : cmd->argv[2],
                              pubkey ? silc_buffer_len(args) :
                              cmd->argv_lens[2]);
@@ -2409,6 +2463,7 @@ SILC_FSM_STATE(silc_client_command_leave)
 {
   SilcClientCommandContext cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
+  SilcClient client = conn->client;
   SilcChannelEntry channel;
   SilcBuffer idp;
   char *name;
@@ -2437,7 +2492,7 @@ SILC_FSM_STATE(silc_client_command_leave)
     goto out;
   }
 
-  idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  idp = silc_id_payload_encode(&channel->id, SILC_ID_CHANNEL);
 
   /* Send LEAVE command to the server */
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1,
@@ -2451,6 +2506,8 @@ SILC_FSM_STATE(silc_client_command_leave)
   if (conn->current_channel == channel)
     conn->current_channel = NULL;
 
+  silc_client_unref_channel(client, conn, channel);
+
   /** Wait for command reply */
   silc_fsm_next(fsm, silc_client_command_reply_wait);
   return SILC_FSM_CONTINUE;
@@ -2525,12 +2582,10 @@ SILC_FSM_STATE(silc_client_command_getkey)
   }
 
   /* Parse the typed nickname. */
-  if (client->internal->params->nickname_parse)
-    client->internal->params->nickname_parse(cmd->argv[1], &nickname);
-  else
-    nickname = strdup(cmd->argv[1]);
-  if (!nickname)
+  if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname)) {
+    COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT);
     return SILC_FSM_FINISH;
+  }
 
   /* Find client entry */
   clients = silc_client_get_clients_local(client, conn, nickname,
@@ -2539,7 +2594,16 @@ SILC_FSM_STATE(silc_client_command_getkey)
     /* Check whether user requested server */
     server_entry = silc_client_get_server(client, conn, cmd->argv[1]);
     if (!server_entry) {
+      if (cmd->resolved) {
+       /* Resolving didn't find anything.  We should never get here as
+          errors are handled in the resolving callback. */
+       COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
+       COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_SERVER);
+       return SILC_FSM_FINISH;
+      }
+
       /* No client or server exist with this name, query for both. */
+      cmd->resolved = TRUE;
       SILC_FSM_CALL(silc_client_command_send(client, conn,
                                             SILC_COMMAND_IDENTIFY,
                                             silc_client_command_continue,
@@ -2548,8 +2612,10 @@ SILC_FSM_STATE(silc_client_command_getkey)
                                             strlen(cmd->argv[1]),
                                             2, cmd->argv[1],
                                             strlen(cmd->argv[1])));
+      /* NOT REACHED */
     }
-    idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER);
+    idp = silc_id_payload_encode(&server_entry->id, SILC_ID_SERVER);
+    silc_client_unref_server(client, conn, server_entry);
   } else {
     client_entry = silc_dlist_get(clients);
     idp = silc_id_payload_encode(&client_entry->id, SILC_ID_CLIENT);
@@ -2748,10 +2814,8 @@ SILC_FSM_STATE(silc_client_command)
   payload = silc_command_payload_parse(packet->buffer.data,
                                       silc_buffer_len(&packet->buffer));
   if (!payload) {
-    /** Bad command payload */
     SILC_LOG_DEBUG(("Bad command packet"));
-    silc_fsm_next(fsm, silc_client_connection_st_packet);
-    return SILC_FSM_CONTINUE;
+    return SILC_FSM_FINISH;
   }
 
   /* Get arguments */
@@ -2763,7 +2827,7 @@ SILC_FSM_STATE(silc_client_command)
 
   case SILC_COMMAND_WHOIS:
     /* Ignore everything if requested by application */
-    if (client->internal->params->ignore_requested_attributes)
+    if (conn->internal->params.ignore_requested_attributes)
       break;
 
     silc_client_command_process_whois(client, conn, payload, args);
@@ -2774,8 +2838,5 @@ SILC_FSM_STATE(silc_client_command)
   }
 
   silc_command_payload_free(payload);
-
-  /** Packet processed */
-  silc_fsm_next(fsm, silc_client_connection_st_packet);
-  return SILC_FSM_CONTINUE;
+  return SILC_FSM_FINISH;
 }