updates.
[silc.git] / lib / silcclient / command.c
index 002363fb305077eb4b8410759d1bd845275e2e3b..a97cdc0d951780c4d16f73c2c2464a6373bc59f6 100644 (file)
@@ -58,6 +58,7 @@ SilcClientCommand silc_command_list[] =
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 3),
   SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
   SILC_CLIENT_CMD(users, USERS, "USERS", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(ban, BAN, "BAN", SILC_CF_LAG | SILC_CF_REG, 3),
 
   { NULL, 0, NULL, 0, 0 },
 };
@@ -529,18 +530,20 @@ SILC_CLIENT_CMD_FUNC(topic)
   silc_client_command_free(cmd);
 }
 
-/* Command INVITE. Invites specific client to join a channel. */
+/* Command INVITE. Invites specific client to join a channel. This is
+   also used to mange the invite list of the channel. */
 
 SILC_CLIENT_CMD_FUNC(invite)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClient client = cmd->client;
   SilcClientConnection conn = cmd->conn;
-  SilcClientEntry client_entry;
-  SilcChannelEntry channel_entry;
+  SilcClientEntry client_entry = NULL;
+  SilcChannelEntry channel;
   SilcBuffer buffer, clidp, chidp;
-  unsigned int num = 0;
-  char *nickname = NULL, *server = NULL;
+  unsigned int num = 0, type = 0;
+  char *nickname = NULL, *server = NULL, *name;
+  char *invite = NULL;
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -548,63 +551,104 @@ SILC_CLIENT_CMD_FUNC(invite)
     goto out;
   }
 
-  if (cmd->argc != 3) {
+  if (cmd->argc < 2) {
     cmd->client->ops->say(cmd->client, conn,
-                         "Usage: /INVITE <nickname>[@<server>] <channel>");
+                  "Usage: /INVITE <channel> [<nickname>[@server>]"
+                  "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
     COMMAND_ERROR;
     goto out;
   }
 
-  /* Parse the typed nickname. */
-  if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
-    cmd->client->ops->say(cmd->client, conn, "Bad nickname");
-    COMMAND_ERROR;
-    goto out;
-  }
+  if (cmd->argv[1][0] == '*') {
+    if (!conn->current_channel) {
+      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      COMMAND_ERROR;
+      goto out;
+    }
 
-  /* Find client entry */
-  client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
-                                       TRUE);
-  if (!client_entry) {
-    if (nickname)
-      silc_free(nickname);
-    if (server)
-      silc_free(server);
+    channel = conn->current_channel;
+  } else {
+    name = cmd->argv[1];
 
-    /* Client entry not found, it was requested thus mark this to be
-       pending command. */
-    silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
-                               silc_client_command_destructor,
-                               silc_client_command_invite, 
-                               silc_client_command_dup(cmd));
-    cmd->pending = 1;
-    return;
+    channel = silc_client_get_channel(cmd->client, conn, name);
+    if (!channel) {
+      cmd->client->ops->say(cmd->client, conn, "You are on that channel");
+      COMMAND_ERROR;
+      goto out;
+    }
   }
 
-  /* Find channel entry */
-  channel_entry = silc_client_get_channel(client, conn, cmd->argv[2]);
-  if (!channel_entry) {
-    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
-    COMMAND_ERROR;
-    goto out;
+  /* Parse the typed nickname. */
+  if (cmd->argc == 3) {
+    if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
+      if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
+       cmd->client->ops->say(cmd->client, conn, "Bad nickname");
+       COMMAND_ERROR;
+       goto out;
+      }
+      
+      /* Find client entry */
+      client_entry = silc_idlist_get_client(client, conn, nickname, 
+                                           server, num, TRUE);
+      if (!client_entry) {
+       if (nickname)
+         silc_free(nickname);
+       if (server)
+         silc_free(server);
+       
+       if (cmd->pending) {
+         COMMAND_ERROR;
+         goto out;
+       }
+      
+       /* Client entry not found, it was requested thus mark this to be
+          pending command. */
+       silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
+                                   conn->cmd_ident,
+                                   silc_client_command_destructor,
+                                   silc_client_command_invite, 
+                                   silc_client_command_dup(cmd));
+       cmd->pending = 1;
+       return;
+      }
+      
+      cmd->client->ops->say(cmd->client, conn, 
+                           "Inviting %s to channel %s", cmd->argv[2], 
+                           channel->channel_name);
+    } else {
+      invite = cmd->argv[2];
+      invite++;
+      if (cmd->argv[2][0] == '+')
+       type = 3;
+      else
+       type = 4;
+    }
+  }
+
+  /* Send the command */
+  chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  if (client_entry) {
+    clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 
+                                           ++conn->cmd_ident, 3,
+                                           1, chidp->data, chidp->len,
+                                           2, clidp->data, clidp->len,
+                                           type, invite, invite ?
+                                           strlen(invite) : 0);
+    silc_buffer_free(clidp);
+  } else {
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 
+                                           ++conn->cmd_ident, 2,
+                                           1, chidp->data, chidp->len,
+                                           type, invite, invite ?
+                                           strlen(invite) : 0);
   }
 
-  /* Send command */
-  clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
-  chidp = silc_id_payload_encode(channel_entry->id, SILC_ID_CHANNEL);
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 0, 2,
-                                         1, clidp->data, clidp->len,
-                                         2, chidp->data, chidp->len);
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
-  silc_buffer_free(clidp);
   silc_buffer_free(chidp);
 
-  cmd->client->ops->say(cmd->client, conn, 
-                       "Inviting %s to channel %s", cmd->argv[1], 
-                       cmd->argv[2]);
-
   /* Notify application */
   COMMAND;
 
@@ -627,7 +671,7 @@ SILC_TASK_CALLBACK(silc_client_command_quit_cb)
 
   /* Close connection */
   q->client->ops->disconnect(q->client, q->conn);
-  silc_client_close_connection(q->client, q->conn->sock->user_data);
+  silc_client_close_connection(q->client, NULL, q->conn->sock->user_data);
 
   silc_free(q);
 }
@@ -714,6 +758,11 @@ SILC_CLIENT_CMD_FUNC(kill)
     if (server)
       silc_free(server);
 
+    if (cmd->pending) {
+      COMMAND_ERROR;
+      goto out;
+    }
+
     /* Client entry not found, it was requested thus mark this to be
        pending command. */
     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
@@ -743,21 +792,6 @@ SILC_CLIENT_CMD_FUNC(kill)
   /* Notify application */
   COMMAND;
 
-  /* Remove the client entry to be killed */
-  silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, 
-                        target->id);
-  if (target->nickname)
-    silc_free(target->nickname);
-  if (target->server)
-    silc_free(target->server);
-  if (target->id)
-    silc_free(target->id);
-  if (target->send_key)
-    silc_cipher_free(target->send_key);
-  if (target->receive_key)
-    silc_cipher_free(target->receive_key);
-  silc_free(target);
-
  out:
   if (nickname)
     silc_free(nickname);
@@ -1037,6 +1071,12 @@ SILC_CLIENT_CMD_FUNC(umode)
       else
        mode &= ~SILC_UMODE_ROUTER_OPERATOR;
       break;
+    case 'g':
+      if (add)
+       mode |= SILC_UMODE_GONE;
+      else
+       mode &= ~SILC_UMODE_GONE;
+      break;
     default:
       COMMAND_ERROR;
       goto out;
@@ -1074,7 +1114,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
   SilcChannelEntry channel;
-  SilcBuffer buffer, chidp;
+  SilcBuffer buffer, chidp, auth = NULL;
   unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
   unsigned int mode, add, type, len, arg_len = 0;
   int i;
@@ -1180,34 +1220,46 @@ SILC_CLIENT_CMD_FUNC(cmode)
        mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
       }
       break;
-    case 'b':
+    case 'c':
       if (add) {
-       mode |= SILC_CHANNEL_MODE_BAN;
+       mode |= SILC_CHANNEL_MODE_CIPHER;
        type = 5;
        arg = cmd->argv[3];
        arg_len = cmd->argv_lens[3];
       } else {
-       mode &= ~SILC_CHANNEL_MODE_BAN;
+       mode &= ~SILC_CHANNEL_MODE_CIPHER;
       }
       break;
-    case 'I':
+    case 'h':
       if (add) {
-       mode |= SILC_CHANNEL_MODE_INVITE_LIST;
+       mode |= SILC_CHANNEL_MODE_HMAC;
        type = 6;
        arg = cmd->argv[3];
        arg_len = cmd->argv_lens[3];
       } else {
-       mode &= ~SILC_CHANNEL_MODE_INVITE_LIST;
+       mode &= ~SILC_CHANNEL_MODE_HMAC;
       }
       break;
-    case 'c':
+    case 'f':
       if (add) {
-       mode |= SILC_CHANNEL_MODE_CIPHER;
-       type = 8;
-       arg = cmd->argv[3];
-       arg_len = cmd->argv_lens[3];
+       mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
+       type = 7;
+
+       if (!strcasecmp(cmd->argv[3], "-pubkey")) {
+         auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+                                                   cmd->client->private_key,
+                                                   conn->hash,
+                                                   conn->local_id,
+                                                   SILC_ID_CLIENT);
+       } else {
+         auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
+                                         cmd->argv[3], cmd->argv_lens[3]);
+       }
+
+       arg = auth->data;
+       arg_len = auth->len;
       } else {
-       mode &= ~SILC_CHANNEL_MODE_CIPHER;
+       mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
       }
       break;
     default:
@@ -1244,6 +1296,8 @@ SILC_CLIENT_CMD_FUNC(cmode)
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(chidp);
+  if (auth)
+    silc_buffer_free(auth);
 
   /* Notify application */
   COMMAND;
@@ -1261,7 +1315,7 @@ SILC_CLIENT_CMD_FUNC(cumode)
   SilcChannelEntry channel;
   SilcChannelUser chu;
   SilcClientEntry client_entry;
-  SilcBuffer buffer, clidp, chidp;
+  SilcBuffer buffer, clidp, chidp, auth = NULL;
   unsigned char *name, *cp, modebuf[4];
   unsigned int mode = 0, add, len;
   char *nickname = NULL, *server = NULL;
@@ -1311,6 +1365,11 @@ SILC_CLIENT_CMD_FUNC(cumode)
   client_entry = silc_idlist_get_client(cmd->client, conn, 
                                        nickname, server, num, TRUE);
   if (!client_entry) {
+    if (cmd->pending) {
+      COMMAND_ERROR;
+      goto out;
+    }
+
     /* Client entry not found, it was requested thus mark this to be
        pending command. */
     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
@@ -1349,10 +1408,23 @@ SILC_CLIENT_CMD_FUNC(cumode)
       }
       break;
     case 'f':
-      if (add)
+      if (add) {
+       if (cmd->argc == 5) {
+         if (!strcasecmp(cmd->argv[4], "-pubkey")) {
+         auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+                                                   cmd->client->private_key,
+                                                   conn->hash,
+                                                   conn->local_id,
+                                                   SILC_ID_CLIENT);
+         } else {
+           auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
+                                           cmd->argv[4], cmd->argv_lens[4]);
+         }
+       }
        mode |= SILC_CHANNEL_UMODE_CHANFO;
-      else
+      } else {
        mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+      }
       break;
     case 'o':
       if (add)
@@ -1373,16 +1445,20 @@ SILC_CLIENT_CMD_FUNC(cumode)
 
   /* Send the command packet. We support sending only one mode at once
      that requires an argument. */
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 3
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 4
                                          1, chidp->data, chidp->len, 
                                          2, modebuf, 4,
-                                         3, clidp->data, clidp->len);
-
+                                         3, clidp->data, clidp->len,
+                                         4, auth ? auth->data : NULL, 
+                                         auth ? auth->len : 0);
+  
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(chidp);
   silc_buffer_free(clidp);
+  if (auth)
+    silc_buffer_free(auth);
   
   /* Notify application */
   COMMAND;
@@ -1665,8 +1741,32 @@ SILC_CLIENT_CMD_FUNC(connect)
   silc_client_command_free(cmd);
 }
 
+/* RESTART command. Restarts the server. You must be server operator
+   to be able to use this command. */
+
 SILC_CLIENT_CMD_FUNC(restart)
 {
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcBuffer buffer;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  buffer = silc_command_payload_encode(SILC_COMMAND_RESTART, 0,
+                                      NULL, NULL, NULL, 0);
+  silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND, 
+                         NULL, 0, NULL, NULL, 
+                         buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
 }
 
 /* CLOSE command. Close server connection to the remote server */
@@ -1739,7 +1839,7 @@ SILC_CLIENT_CMD_FUNC(shutdown)
  out:
   silc_client_command_free(cmd);
 }
+
 /* LEAVE command. Leaves a channel. Client removes itself from a channel. */
 
 SILC_CLIENT_CMD_FUNC(leave)
@@ -1937,7 +2037,10 @@ SILC_CLIENT_CMD_FUNC(users)
          strcat(line, " ");
       }
 
-      strncat(line, "  H", 3);
+      if (e->mode & SILC_UMODE_GONE)
+       strcat(line, "  G");
+      else
+       strcat(line, "  H");
       strcat(tmp, m ? m : "");
       strncat(line, tmp, strlen(tmp));
 
@@ -1963,3 +2066,80 @@ SILC_CLIENT_CMD_FUNC(users)
  out:
   silc_client_command_free(cmd);
 }
+
+/* Command BAN. This is used to manage the ban list of the channel. */
+
+SILC_CLIENT_CMD_FUNC(ban)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcChannelEntry channel;
+  SilcBuffer buffer, chidp;
+  int type = 0;
+  char *name, *ban = NULL;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc < 2) {
+    cmd->client->ops->say(cmd->client, conn, 
+                  "Usage: /BAN <channel> "
+                  "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argv[1][0] == '*') {
+    if (!conn->current_channel) {
+      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      COMMAND_ERROR;
+      goto out;
+    }
+
+    channel = conn->current_channel;
+  } else {
+    name = cmd->argv[1];
+
+    channel = silc_client_get_channel(cmd->client, conn, name);
+    if (!channel) {
+      cmd->client->ops->say(cmd->client, conn, "You are on that channel");
+      COMMAND_ERROR;
+      goto out;
+    }
+  }
+
+  if (cmd->argc == 3) {
+    if (cmd->argv[2][0] == '+')
+      type = 2;
+    else
+      type = 3;
+
+    ban = cmd->argv[2];
+    ban++;
+  }
+
+  chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+
+  /* Send the command */
+  if (ban)
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 2, 
+                                           1, chidp->data, chidp->len,
+                                           type, ban, strlen(ban));
+  else
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 0, 1, 
+                                           1, chidp->data, chidp->len);
+
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+                         0, NULL, NULL, buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+  silc_buffer_free(chidp);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}