Rewrote WHOIS command and attributes handling.
[silc.git] / lib / silcclient / command.c
index ade3e1b82702ff68d9ee4438378ac3c02d933893..f221b3749d0040da52f4f36374599439245a8f69 100644 (file)
@@ -123,6 +123,32 @@ static void silc_client_command_resolve_continue(SilcClient client,
   SILC_FSM_CALL_CONTINUE(&cmd->thread);
 }
 
+/* Dummy command callback.  Nothing interesting to do here.  Use this when
+   you just send command but don't care about reply. */
+
+SilcBool silc_client_command_called_dummy(SilcClient client,
+                                         SilcClientConnection conn,
+                                         SilcCommand command,
+                                         SilcStatus status,
+                                         SilcStatus error,
+                                         void *context,
+                                         va_list ap)
+{
+  return FALSE;
+}
+
+/* Dummy resolving callback.  Nothing interesting to do here.  Use this
+   when you just resolve entires but don't care about reply. */
+
+void silc_client_command_resolve_dummy(SilcClient client,
+                                      SilcClientConnection conn,
+                                      SilcStatus status,
+                                      SilcDList clients,
+                                      void *context)
+{
+  /* Nothing */
+}
+
 /* Register command to client */
 
 static SilcBool
@@ -390,7 +416,7 @@ SilcUInt16 silc_client_command_call(SilcClient client,
   char *arg;
 
   if (!conn) {
-    client->internal->ops->say(client, NULL, SILC_CLIENT_MESSAGE_ERROR,
+    client->internal->ops->say(client, NULL, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
       "You are not connected to a server, please connect to server");
     return 0;
   }
@@ -670,7 +696,7 @@ SILC_FSM_STATE(silc_client_command_whois)
     SilcPublicKey pk;
 
     if (!silc_pkcs_load_public_key(pubkey, &pk)) {
-      SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+      SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
          "Could not load public key %s, check the filename",
          pubkey);
       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
@@ -797,7 +823,7 @@ SILC_FSM_STATE(silc_client_command_identify)
 
 SILC_FSM_STATE(silc_client_command_nick)
 {
-  SilcClientCommandContext cmd = fsm_context;
+  SilcClientCommandContext cmd2, cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
 
   if (cmd->argc < 2) {
@@ -825,6 +851,19 @@ SILC_FSM_STATE(silc_client_command_nick)
     goto out;
   }
 
+  /* If JOIN command is active, wait for it to finish before sending NICK.
+     To avoid problems locally with changing IDs while joining, we do this. */
+  silc_mutex_lock(conn->internal->lock);
+  silc_list_start(conn->internal->pending_commands);
+  while ((cmd2 = silc_list_get(conn->internal->pending_commands))) {
+    if (cmd2->cmd == SILC_COMMAND_JOIN) {
+      silc_mutex_unlock(conn->internal->lock);
+      silc_fsm_next_later(fsm, silc_client_command_nick, 0, 300000);
+      return SILC_FSM_WAIT;
+    }
+  }
+  silc_mutex_unlock(conn->internal->lock);
+
   if (cmd->argv_lens[1] > 128)
     cmd->argv_lens[1] = 128;
 
@@ -1121,7 +1160,6 @@ SILC_FSM_STATE(silc_client_command_quit)
 
 /********************************** KILL ************************************/
 
-
 /* Command KILL. Router operator can use this command to remove an client
    fromthe SILC Network. */
 
@@ -1275,7 +1313,7 @@ SILC_FSM_STATE(silc_client_command_ping)
 
 SILC_FSM_STATE(silc_client_command_join)
 {
-  SilcClientCommandContext cmd = fsm_context;
+  SilcClientCommandContext cmd2, cmd = fsm_context;
   SilcClientConnection conn = cmd->conn;
   SilcClient client = conn->client;
   SilcChannelEntry channel = NULL;
@@ -1293,6 +1331,19 @@ SILC_FSM_STATE(silc_client_command_join)
   if (channel && silc_client_on_channel(channel, conn->local_entry))
     goto out;
 
+  /* If NICK command is active, wait for it to finish before sending JOIN.
+     To avoid problems locally with changing IDs while joining, we do this. */
+  silc_mutex_lock(conn->internal->lock);
+  silc_list_start(conn->internal->pending_commands);
+  while ((cmd2 = silc_list_get(conn->internal->pending_commands))) {
+    if (cmd2->cmd == SILC_COMMAND_NICK) {
+      silc_mutex_unlock(conn->internal->lock);
+      silc_fsm_next_later(fsm, silc_client_command_join, 0, 300000);
+      return SILC_FSM_WAIT;
+    }
+  }
+  silc_mutex_unlock(conn->internal->lock);
+
   if (cmd->argv_lens[1] > 256)
     cmd->argv_lens[1] = 256;
 
@@ -1324,7 +1375,7 @@ SILC_FSM_STATE(silc_client_command_join)
        }
        if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
                                &pubkey, &privkey)) {
-         SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+         SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
              "Could not load key pair, check your arguments");
          COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
          goto out;
@@ -1744,7 +1795,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
            pass = cmd->argv[5];
          if (!silc_load_key_pair(cmd->argv[3], cmd->argv[4], pass,
                                  &pubkey, &privkey)) {
-           SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+           SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
                "Could not load key pair, check your arguments");
            COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
            goto out;
@@ -1796,7 +1847,7 @@ SILC_FSM_STATE(silc_client_command_cmode)
          if (cmd->argv[k][0] == '+')
            chadd = TRUE;
          if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk)) {
-           SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+           SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
                "Could not load public key %s, check the filename",
                cmd->argv[k]);
            COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
@@ -1958,7 +2009,7 @@ SILC_FSM_STATE(silc_client_command_cumode)
            pass = cmd->argv[6];
          if (!silc_load_key_pair(cmd->argv[4], cmd->argv[5], pass,
                                  &pubkey, &privkey)) {
-           SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+           SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
                "Could not load key pair, check your arguments");
            COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
            goto out;
@@ -2411,7 +2462,7 @@ SILC_FSM_STATE(silc_client_command_watch)
     SilcBuffer buffer;
 
     if (!silc_pkcs_load_public_key(pubkey, &pk)) {
-      SAY(conn->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+      SAY(conn->client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
          "Could not load public key %s, check the filename", pubkey);
       COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
       goto out;
@@ -2428,6 +2479,12 @@ SILC_FSM_STATE(silc_client_command_watch)
     silc_pkcs_public_key_free(pk);
   }
 
+  /* If watching by nickname, resolve all users with that nickname so that
+     we get their information immediately. */
+  if (type == 2)
+    silc_client_get_clients(conn->client, conn, cmd->argv[2], NULL,
+                           silc_client_command_resolve_dummy, NULL);
+
   /* Send the commmand */
   silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2,
                              1, silc_buffer_datalen(conn->internal->
@@ -2750,7 +2807,6 @@ static void silc_client_command_process_whois(SilcClient client,
                                              SilcCommandPayload payload,
                                              SilcArgumentPayload args)
 {
-#if 0
   SilcDList attrs;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
@@ -2774,18 +2830,25 @@ static void silc_client_command_process_whois(SilcClient client,
     return;
   }
 
-  /* Send the attributes back */
+  /* Send the attributes back in COMMAND_REPLY packet */
   packet =
     silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
                                         SILC_STATUS_OK, 0,
                                         silc_command_get_ident(payload),
-                                        1, 11, buffer->data, buffer->len);
-  silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
-                         NULL, 0, NULL, NULL, packet->data,
-                         packet->len, TRUE);
+                                        1, 11, buffer->data,
+                                        silc_buffer_len(buffer));
+  if (!packet) {
+    silc_buffer_free(buffer);
+    return;
+  }
+
+  SILC_LOG_DEBUG(("Sending back requested WHOIS attributes"));
+
+  silc_packet_send(conn->stream, SILC_PACKET_COMMAND_REPLY, 0,
+                  silc_buffer_datalen(packet));
+
   silc_buffer_free(packet);
   silc_buffer_free(buffer);
-#endif /* 0 */
 }
 
 /* Client is able to receive some command packets even though they are