implemented KICK command
authorPekka Riikonen <priikone@silcnet.org>
Sat, 24 Feb 2001 15:50:23 +0000 (15:50 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sat, 24 Feb 2001 15:50:23 +0000 (15:50 +0000)
19 files changed:
CHANGES
README
apps/silc/client_ops.c
apps/silc/local_command.c
apps/silcd/command.c
apps/silcd/packet_receive.c
apps/silcd/packet_send.c
apps/silcd/packet_send.h
apps/silcd/testi2.conf
doc/draft-riikonen-silc-pp-01.nroff
doc/draft-riikonen-silc-spec-01.nroff
lib/silcclient/client.c
lib/silcclient/command.c
lib/silcclient/command_reply.c
lib/silcclient/idlist.c
lib/silcclient/idlist.h
lib/silccore/id.c
lib/silccore/silccommand.h
lib/silccore/silcnotify.h

diff --git a/CHANGES b/CHANGES
index 23617be1e3b0a1c04fb4bab838cc5fb5f1ad1841..da495f1f3dc8f0484ef2f3fa3510e8baa4270607 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,23 @@
+Sat Feb 24 16:03:45 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added SILC_NOTIFY_TYPE_KICKED to indicate that the client
+         or some other client was kicked from the channel.
+
+         Implemented the handling of the notify type to both client
+         and server.
+
+         Implemented silc_server_send_notify_kicked to send the KICKED
+         notify.  It is used to send it to the server's primary router.
+
+       * Implemented the KICK command into server and client.
+
+       * Added `query' argument to the silc_idlist_get_client function
+         to indicate whether to query the client from server or not if
+         it was not found.
+
+       * Added new command status type SILC_STATUS_ERR_NO_CHANNEL_FOPRIV
+         to indicate that the client is not channel founder.
+
 Sat Feb 24 00:00:55 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Removed the rng context from SilcPacketContext structure and
diff --git a/README b/README
index f37377ac669adbe8ba05199805ef02746635b58e..e25a8451e1c434ed50a8121c160e25df0bc47ba2 100644 (file)
--- a/README
+++ b/README
@@ -130,6 +130,13 @@ Following commands has been, at least partly, implemented:
                handling multiple same nicknames with this command is
                still missing.
 
+        /KICK   <channel> <nickname>[@<server>] [<comment>]
+
+                Kicks client from channel. You have to be at least channel
+               operator to be able to kick client from channel.  Note:
+               you cannot kick channel founder even if you are channel
+               operator.
+
        /PING   [<server>]
 
                Pings server.  Only locally connected server may be 
index 830c6e9004d1be1f233998c12761ddc6f9d5261d..48ba11526bd53325064bbad1f508b91376b58588 100644 (file)
@@ -229,6 +229,27 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
   case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
     break;
 
+  case SILC_NOTIFY_TYPE_KICKED:
+    client_entry = va_arg(vp, SilcClientEntry);
+    tmp = va_arg(vp, char *);
+    channel_entry = va_arg(vp, SilcChannelEntry);
+
+    if (client_entry == conn->local_entry) {
+      snprintf(message, sizeof(message), 
+              "You have been kicked off channel %s %s%s%s", 
+              conn->current_channel->channel_name,
+              tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
+    } else {
+      snprintf(message, sizeof(message), 
+              "%s%s%s has been kicked off channel %s %s%s%s", 
+              client_entry->nickname, 
+              client_entry->server ? "@" : "",
+              client_entry->server ? client_entry->server : "",
+              conn->current_channel->channel_name,
+              tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
+    }
+    break;
+
   default:
     break;
   }
index b96c80d1e5f0259923bb7ad968dc6038692b1d14..58a76660ce2ce505aa1068140c5e6f19f591f818 100644 (file)
@@ -20,6 +20,9 @@
 /*
  * $Id$
  * $Log$
+ * Revision 1.6  2001/02/24 15:50:23  priikone
+ *     implemented KICK command
+ *
  * Revision 1.5  2001/02/19 13:47:30  priikone
  *     updates.
  *
@@ -145,7 +148,8 @@ SILC_CLIENT_LCMD_FUNC(msg)
   }
 
   /* Find client entry */
-  client_entry = silc_idlist_get_client(client, conn, nickname, server, num);
+  client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
+                                       TRUE);
   if (!client_entry) {
     /* Client entry not found, it was requested thus mark this to be
        pending command. */
index 188c04cac8c0421383229208c4436e3085dd7706..05c385d6bb3667443f5bab9e601848f2ba4740c8 100644 (file)
@@ -2386,7 +2386,7 @@ SILC_SERVER_CMD_FUNC(cmode)
     if (!tmp) {
       if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+                                  SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
        goto out;
       }
     } else {
@@ -2407,7 +2407,7 @@ SILC_SERVER_CMD_FUNC(cmode)
       tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
       if (!tmp) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+                                  SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
        goto out;
       }
 
@@ -2432,7 +2432,7 @@ SILC_SERVER_CMD_FUNC(cmode)
       tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
       if (!tmp) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+                                  SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
        goto out;
       }
 
@@ -2459,7 +2459,7 @@ SILC_SERVER_CMD_FUNC(cmode)
       tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
       if (!tmp) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+                                  SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
        goto out;
       }
 
@@ -2700,13 +2700,13 @@ SILC_SERVER_CMD_FUNC(cumode)
   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
   if (!tmp_id) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+                                         SILC_STATUS_ERR_NO_CLIENT_ID);
     goto out;
   }
   client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
   if (!client_id) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+                                         SILC_STATUS_ERR_NO_CLIENT_ID);
     goto out;
   }
 
@@ -2818,6 +2818,151 @@ SILC_SERVER_CMD_FUNC(cumode)
 
 SILC_SERVER_CMD_FUNC(kick)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcClientEntry target_client;
+  SilcChannelID *channel_id;
+  SilcClientID *client_id;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+  SilcBuffer idp;
+  unsigned int tmp_len;
+  unsigned char *tmp, *comment;
+
+  SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 3);
+
+  /* Get Channel ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+  if (!channel_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+
+  /* Get channel entry */
+  channel = silc_idlist_find_channel_by_id(server->local_list, 
+                                          channel_id, NULL);
+  if (!channel) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+                                         SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+    goto out;
+  }
+
+  /* Check whether sender is on the channel */
+  if (!silc_server_client_on_channel(client, channel)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+                                         SILC_STATUS_ERR_NOT_ON_CHANNEL);
+    goto out;
+  }
+
+  /* Check that the kicker is channel operator or channel founder */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    if (chl->client == client) {
+      if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+       goto out;
+      }
+      break;
+    }
+  }
+  
+  /* Get target Client ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+                                         SILC_STATUS_ERR_NO_CLIENT_ID);
+    goto out;
+  }
+  client_id = silc_id_payload_parse_id(tmp, tmp_len);
+  if (!client_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+                                         SILC_STATUS_ERR_NO_CLIENT_ID);
+    goto out;
+  }
+
+  /* Get target client's entry */
+  target_client = silc_idlist_find_client_by_id(server->local_list, 
+                                               client_id, NULL);
+  if (!target_client) {
+    target_client = silc_idlist_find_client_by_id(server->global_list, 
+                                                 client_id, NULL);
+  }
+
+  /* Check that the target client is not channel founder. Channel founder
+     cannot be kicked from the channel. */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    if (chl->client == target_client) {
+      if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+                                 SILC_STATUS_ERR_NO_CHANNEL_FOPRIV);
+       goto out;
+      }
+      break;
+    }
+  }
+  
+  /* Check whether target client is on the channel */
+  if (!silc_server_client_on_channel(target_client, channel)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+                                         SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
+    goto out;
+  }
+
+  /* Get comment */
+  tmp_len = 0;
+  comment = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+  if (tmp_len > 128)
+    comment = NULL;
+
+  /* Send command reply to sender */
+  silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK, 
+                                       SILC_STATUS_OK);
+
+  /* Send KICKED notify to local clients on the channel */
+  idp = silc_id_payload_encode(target_client->id, SILC_ID_CLIENT);
+  silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+                                    SILC_NOTIFY_TYPE_KICKED, 
+                                    comment ? 2 : 1,
+                                    idp->data, idp->len,
+                                    comment, comment ? strlen(comment) : 0);
+  silc_buffer_free(idp);
+
+  /* Remove the client from the channel. If the channel does not exist
+     after removing the client then the client kicked itself of the channel
+     and we don't have to send anything after that. */
+  if (!silc_server_remove_from_one_channel(server, NULL, channel, 
+                                          target_client, FALSE))
+    goto out;
+
+  /* Send KICKED notify to primary route */
+  if (!server->standalone)
+    silc_server_send_notify_kicked(server, server->router->connection,
+                                  server->server_type == SILC_ROUTER ?
+                                  TRUE : FALSE, channel,
+                                  target_client->id, SILC_ID_CLIENT_LEN,
+                                  comment);
+
+  /* Re-generate channel key */
+  silc_server_create_channel_key(server, channel, 0);
+
+  /* Send the channel key to the channel. The key of course is not sent
+     to the client who joined the channel. */
+  silc_server_send_channel_key(server, target_client->connection, channel, 
+                              server->server_type == SILC_ROUTER ? 
+                              FALSE : server->standalone);
+
+ out:
+  silc_server_command_free(cmd);
 }
 
 SILC_SERVER_CMD_FUNC(restart)
index 3c66a9125cf57c8ca1743fcd02e2912613011e59..16ae24db06595cbc3f0e8aa131826e245d395b5b 100644 (file)
@@ -479,6 +479,61 @@ void silc_server_notify(SilcServer server,
     SILC_LOG_DEBUG(("SERVER SIGNOFF notify (not-impl XXX)"));
     break;
 
+  case SILC_NOTIFY_TYPE_KICKED:
+    /* 
+     * Distribute the notify to local clients on the channel
+     */
+    
+    SILC_LOG_DEBUG(("KICKED notify"));
+      
+    channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                               packet->dst_id_type);
+    if (!channel_id)
+      goto out;
+
+    /* Get channel entry */
+    channel = silc_idlist_find_channel_by_id(server->local_list, 
+                                            channel_id, NULL);
+    if (!channel) {
+      channel = silc_idlist_find_channel_by_id(server->global_list, 
+                                              channel_id, NULL);
+      if (!channel) {
+       silc_free(channel_id);
+       goto out;
+      }
+    }
+    silc_free(channel_id);
+
+    /* Get client ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!client_id)
+      goto out;
+
+    /* Send to channel */
+    silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
+                                      FALSE, packet->buffer->data, 
+                                      packet->buffer->len, FALSE);
+
+    /* If the the client is not in local list we check global list */
+    client = silc_idlist_find_client_by_id(server->local_list, 
+                                          client_id, NULL);
+    if (!client) {
+      client = silc_idlist_find_client_by_id(server->global_list, 
+                                            client_id, NULL);
+      if (!client) {
+       silc_free(client_id);
+       goto out;
+      }
+    }
+
+    /* Remove the client from channel */
+    silc_server_remove_from_one_channel(server, sock, channel, client, FALSE);
+
+    break;
+
     /* Ignore rest of the notify types for now */
   case SILC_NOTIFY_TYPE_NONE:
   case SILC_NOTIFY_TYPE_MOTD:
index 4bebe1837d429b9cfb0f69471455f03545704281..b8c720c61b429ec5bd8b04aec8bdb6813ad128de 100644 (file)
@@ -918,6 +918,29 @@ void silc_server_send_notify_topic_set(SilcServer server,
   silc_buffer_free(idp);
 }
 
+/* Send KICKED notify type. This tells that the `client_id' on `channel'
+   was kicked off the channel.  The `comment' may indicate the reason
+   for the kicking. This function is used only between server and router
+   traffic. */
+
+void silc_server_send_notify_kicked(SilcServer server,
+                                   SilcSocketConnection sock,
+                                   int broadcast,
+                                   SilcChannelEntry channel,
+                                   SilcClientID *client_id,
+                                   unsigned int client_id_len,
+                                   char *comment)
+{
+  SilcBuffer idp;
+
+  idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+  silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
+                              SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_KICKED,
+                              comment ? 2 : 1, idp->data, idp->len,
+                              comment, comment ? strlen(comment) : 0);
+  silc_buffer_free(idp);
+}
+
 /* Sends notify message destined to specific entity. */
 
 void silc_server_send_notify_dest(SilcServer server,
@@ -941,7 +964,7 @@ void silc_server_send_notify_dest(SilcServer server,
 }
 
 /* Sends notify message to a channel. The notify message sent is 
-   distributed to all clients on the channel. If `router_notify' is TRUE
+   distributed to all clients on the channel. If `route_notify' is TRUE
    then the notify may be routed to primary route or to some other routers.
    If FALSE it is assured that the notify is sent only locally. If `sender'
    is provided then the packet is not sent to that connection since it
index 827e609c38acde9701c5e4521213a9ae87439a4e..87b072f66a7b46c39fe21fb448f6cb8ee6826a4a 100644 (file)
@@ -144,6 +144,13 @@ void silc_server_send_notify_topic_set(SilcServer server,
                                       SilcClientID *client_id,
                                       unsigned int client_id_len,
                                       char *topic);
+void silc_server_send_notify_kicked(SilcServer server,
+                                   SilcSocketConnection sock,
+                                   int broadcast,
+                                   SilcChannelEntry channel,
+                                   SilcClientID *client_id,
+                                   unsigned int client_id_len,
+                                   char *comment);
 void silc_server_send_notify_dest(SilcServer server,
                                  SilcSocketConnection sock,
                                  int broadcast,
index fe6247a1d0a8b9ff75a693d83810e3924412a3a0..0ece9ca0eb15e69e1ae9da619e89e219cc856ee0 100644 (file)
@@ -19,10 +19,10 @@ nobody:nobody
 Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
 
 [ServerInfo]
-lassi.kuo.fi.ssh.com:10.2.1.7:Kuopio, Finland:1334
+lassi.kuo.fi.ssh.com:212.146.42.253:Kuopio, Finland:1334
 
 [ListenPort]
-10.2.1.7:10.2.1.7:1334
+212.146.42.253:212.146.42.253:1334
 
 [Logging]
 infologfile:silcd2.log:10000
@@ -43,10 +43,10 @@ errorlogfile:silcd2.log:10000
 [AdminConnection]
 
 [ServerConnection]
-10.2.1.7:passwd:priikone:1333:1:1
+212.146.42.253:passwd:priikone:1333:1:1
 
 [RouterConnection]
-10.2.1.7:passwd:priikone:1335:1:1:0
+212.146.42.253:passwd:priikone:1335:1:1:0
 
 [DenyConnection]
 [RedirectClient]
index 30d1be15be25307007fde5948e0781ddd36d7501..7a87af28411de04c2ab7e7f8ba136389e30c4a71 100644 (file)
@@ -1055,7 +1055,7 @@ ID's sent in arguments are sent inside ID Payload.
 
       Sent when client has joined to a channel.  The server must distribute
       this type only to the local clients on the channel and then send
-      it to its primary router. The router or server receiving the packet
+      it to its primary router.  The router or server receiving the packet
       distributes this type to the local clients on the channel and
       broadcast it to the network.
 
@@ -1070,7 +1070,7 @@ ID's sent in arguments are sent inside ID Payload.
 
       Sent when client has left a channel.  The server must distribute
       this type only to the local clients on the channel and then send
-      it to its primary router. The router or server receiving the packet
+      it to its primary router.  The router or server receiving the packet
       distributes this type to the local clients on the channel and
       broadcast it to the network.
 
@@ -1084,7 +1084,7 @@ ID's sent in arguments are sent inside ID Payload.
 
       Sent when client signoffs from SILC network.  The server must
       distribute this type only to the local clients on the channel and
-      then send it to its primary router. The router or server receiving
+      then send it to its primary router.  The router or server receiving
       the packet distributes this type to the local clients on the channel
       and broadcast it to the network.
 
@@ -1184,6 +1184,23 @@ ID's sent in arguments are sent inside ID Payload.
 
       The <Server ID> is the server's ID.
 
+
+12    SILC_NOTIFY_TYPE_KICKED
+
+      Sent when a client has been kicked from a channel.  This is sent 
+      also to the client who was kicked from the channel.  The client
+      who was kicked from the channel must be removed from the channel.
+      This notify type is always destined to the channel.  The router or
+      server receiving the packet distributes this type to the local
+      clients on the channel and broadcast it to the network.
+
+      Max Arguments:  2
+          Arguments:  (1) <Client ID>  (2) [<comment>]
+
+      The <Client ID> is the client who was kicked from the channel.
+      The kicker may have set the <comment> to indicate the reason for
+      the kicking.
+
 .in 3
 
 Notify types starting from 16384 are reserved for private notify
index 088069570b511887dd4f7563391a9a43c7dd81e7..7e9c35cb81ab41852c88cb42c204fdf777887c87 100644 (file)
@@ -2804,7 +2804,7 @@ List of all defined commands in SILC follows.
    19   SILC_COMMAND_KICK
 
         Max Arguments:  3
-            Arguments:  (1) <channel>  (2) <Client ID>  
+            Arguments:  (1) <Channel ID>  (2) <Client ID>  
                         (3) [<comment>]
 
         This command is used by channel operators to remove a client from
@@ -3266,27 +3266,32 @@ List of all defined command status messages following.
         "Permission denied. You are not channel operator".  Command may 
         be executed only by channel operator.
 
-   40   SILC_STATUS_ERR_NO_SERVER_PRIV
+   40   SILC_STATUS_ERR_NO_CHANNEL_FOPRIV
+
+        "Permission denied. You are not channel founder".  Command may 
+        be executed only by channel operator.
+
+   41   SILC_STATUS_ERR_NO_SERVER_PRIV
 
         "Permission denied. You are not server operator".  Command may
         be executed only by server operator.
 
-   41   SILC_STATUS_ERR_NO_ROUTER_PRIV
+   42   SILC_STATUS_ERR_NO_ROUTER_PRIV
 
         "Permission denied. You are not SILC operator".  Command may be
         executed only by router (SILC) operator.
 
-   42   SILC_STATUS_ERR_BAD_NICKNAME
+   43   SILC_STATUS_ERR_BAD_NICKNAME
 
         "Bad nickname".  Nickname requested contained illegal characters
         or were malformed.
 
-   43   SILC_STATUS_ERR_BAD_CHANNEL
+   44   SILC_STATUS_ERR_BAD_CHANNEL
 
         "Bad channel name".  Channel requested contained illegal characters
         or were malformed.
 
-   44   SILC_STATUS_ERR_AUTH_FAILED
+   45   SILC_STATUS_ERR_AUTH_FAILED
 
         "Authentication failed".  The authentication data sent as 
         argument were wrong and thus authentication failed.
index f44ea4e8da0aa7e6f95c50630be4de384ce0338a..8447ee3cc4ab91f0394ab67b1a720efa772641dd 100644 (file)
@@ -1828,6 +1828,59 @@ void silc_client_notify_by_server(SilcClient client,
     /* Notify application */
     client->ops->notify(client, conn, type, channel, channel);
     break;
+
+  case SILC_NOTIFY_TYPE_KICKED:
+    /*
+     * A client (maybe me) was kicked from a channel
+     */
+
+    /* Get Client ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!client_id)
+      goto out;
+
+    /* Find Client entry */
+    client_entry = 
+      silc_idlist_get_client_by_id(client, conn, client_id);
+    if (!client_entry)
+      goto out;
+
+    /* Get channel entry */
+    channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                               SILC_ID_CHANNEL);
+    if (!channel_id)
+      goto out;
+    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                    SILC_ID_CHANNEL, &id_cache))
+      break;
+
+    channel = (SilcChannelEntry)id_cache->context;
+
+    /* Get comment */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+
+    /* Notify application. The channel entry is sent last as this notify
+       is for channel but application don't know it from the arguments
+       sent by server. */
+    client->ops->notify(client, conn, type, client_entry, tmp, channel);
+
+    /* If I was kicked from channel, remove the channel */
+    if (client_entry == conn->local_entry) {
+      if (conn->current_channel == channel)
+       conn->current_channel = NULL;
+      silc_idcache_del_by_id(conn->channel_cache, 
+                            SILC_ID_CHANNEL, channel->id);
+      silc_free(channel->channel_name);
+      silc_free(channel->id);
+      silc_free(channel->key);
+      silc_cipher_free(channel->channel_key);
+      silc_free(channel);
+    }
+    break;
     
   default:
     break;
index 594b13f2591c7ef63fc601dddb4fac47cc252416..8a3e691037b6e0551e3277777a10722adbd43966 100644 (file)
@@ -46,7 +46,7 @@ SilcClientCommand silc_command_list[] =
   SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
   SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4),
   SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", SILC_CF_LAG | SILC_CF_REG, 5),
-  SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 4),
   SILC_CLIENT_CMD(restart, RESTART, "RESTART",
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
   SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
@@ -471,7 +471,8 @@ SILC_CLIENT_CMD_FUNC(invite)
   }
 
   /* Find client entry */
-  client_entry = silc_idlist_get_client(client, conn, nickname, server, num);
+  client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
+                                       TRUE);
   if (!client_entry) {
     if (nickname)
       silc_free(nickname);
@@ -1051,7 +1052,7 @@ SILC_CLIENT_CMD_FUNC(cumode)
 
   /* Find client entry */
   client_entry = silc_idlist_get_client(cmd->client, conn, 
-                                       nickname, server, num);
+                                       nickname, server, num, TRUE);
   if (!client_entry) {
     /* Client entry not found, it was requested thus mark this to be
        pending command. */
@@ -1138,7 +1139,94 @@ SILC_CLIENT_CMD_FUNC(kick)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry channel;
+  SilcBuffer buffer, idp, idp2;
+  SilcClientEntry target;
+  char *name;
+  unsigned int num = 0;
+  char *nickname = NULL, *server = NULL;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc < 3) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Usage: /KICK <channel> <client> [<comment>]");
+    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;
+    }
+    name = conn->current_channel->channel_name;
+  } else {
+    name = cmd->argv[1];
+  }
+
+  if (!conn->current_channel) {
+    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
+    COMMAND_ERROR;
+    goto out;
+  }
 
+  /* Get the Channel ID of the channel */
+  if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
+    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  channel = (SilcChannelEntry)id_cache->context;
+
+  /* Parse the typed nickname. */
+  if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
+    cmd->client->ops->say(cmd->client, conn, "Bad nickname");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  /* Get the target client */
+  target = silc_idlist_get_client(cmd->client, conn, nickname, 
+                                 server, num, FALSE);
+  if (!target) {
+    cmd->client->ops->say(cmd->client, conn, "No such client: %s",
+                         cmd->argv[2]);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  /* Send KICK command to the server */
+  idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
+  idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
+  if (cmd->argc == 3)
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2, 
+                                           1, idp->data, idp->len,
+                                           2, idp2->data, idp2->len);
+  else
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3, 
+                                           1, idp->data, idp->len,
+                                           2, idp2->data, idp2->len,
+                                           3, cmd->argv[3], 
+                                           strlen(cmd->argv[3]));
+  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(idp);
+  silc_buffer_free(idp2);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
 }
 
 SILC_CLIENT_CMD_FUNC(restart)
index 2c576730fa6eab1536abf710e5ce35f002377f61..c026a869182080503136569630e17f8d350278b1 100644 (file)
@@ -107,6 +107,7 @@ const SilcCommandStatusMessage silc_command_status_messages[] = {
   { STAT(UNKNOWN_MODE),    "Unknown mode" },
   { STAT(NOT_YOU),         "Cannot change mode for other users" },
   { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
+  { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
   { STAT(NO_SERVER_PRIV),  "Permission denied. You are not server operator" },
   { STAT(NO_ROUTER_PRIV),  "Permission denied. You are not SILC operator" },
   { STAT(BAD_NICKNAME),    "Bad nickname" },
@@ -1011,6 +1012,29 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode)
 
 SILC_CLIENT_CMD_REPLY_FUNC(kick)
 {
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  unsigned char *tmp;
+
+  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS));
+
+  /* Execute any pending command callbacks */
+  SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
+
+ out:
+  SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
+  silc_client_command_reply_free(cmd);
 }
 
 SILC_CLIENT_CMD_REPLY_FUNC(restart)
index 8da74cafafe066ea7e31aebe16ddf6619243a4fe..0236c812f28ddc836b2f91d62e149cf44bb0c70b 100644 (file)
@@ -31,7 +31,8 @@ SilcClientEntry silc_idlist_get_client(SilcClient client,
                                       SilcClientConnection conn,
                                       char *nickname,
                                       char *server,
-                                      unsigned int num)
+                                      unsigned int num,
+                                      int query)
 {
   SilcIDCacheEntry id_cache;
   SilcIDCacheList list = NULL;
@@ -39,28 +40,31 @@ SilcClientEntry silc_idlist_get_client(SilcClient client,
 
   /* Find ID from cache */
   if (!silc_idcache_find_by_data_loose(conn->client_cache, nickname, &list)) {
-    SilcClientCommandContext ctx;
-    char ident[512];
-    
   identify:
 
-    SILC_LOG_DEBUG(("Requesting Client ID from server"));
-
-    /* No ID found. Do query from the server. The query is done by 
-       sending simple IDENTIFY command to the server. */
-    ctx = silc_client_command_alloc();
-    ctx->client = client;
-    ctx->conn = conn;
-    ctx->command = silc_client_command_find("IDENTIFY");
-    memset(ident, 0, sizeof(ident));
-    snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
-    silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens, 
-                           &ctx->argv_types, &ctx->argc, 2);
-    ctx->command->cb(ctx);
-
-    if (list)
-      silc_idcache_list_free(list);
-
+    if (query) {
+      SilcClientCommandContext ctx;
+      char ident[512];
+      
+      SILC_LOG_DEBUG(("Requesting Client ID from server"));
+      
+      /* No ID found. Do query from the server. The query is done by 
+        sending simple IDENTIFY command to the server. */
+      ctx = silc_client_command_alloc();
+      ctx->client = client;
+      ctx->conn = conn;
+      ctx->command = silc_client_command_find("IDENTIFY");
+      memset(ident, 0, sizeof(ident));
+      snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
+      silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens, 
+                             &ctx->argv_types, &ctx->argc, 2);
+      ctx->command->cb(ctx);
+      
+      if (list)
+       silc_idcache_list_free(list);
+      
+      return NULL;
+    }
     return NULL;
   }
 
index 543d745f2ac5a59204fccf13340422546e106771..4b831db68c91ade45424989c0853f90e9a86256a 100644 (file)
@@ -76,7 +76,8 @@ SilcClientEntry silc_idlist_get_client(SilcClient client,
                                       SilcClientConnection conn,
                                       char *nickname,
                                       char *server,
-                                      unsigned int num);
+                                      unsigned int num,
+                                      int query);
 SilcClientEntry silc_idlist_get_client_by_id(SilcClient client,
                                             SilcClientConnection conn,
                                             SilcClientID *client_id);
index 51e69badd0f189a7242095ed408d569ae28c4d3d..7cb854fc21e985784e1641a7142a85156d10923c 100644 (file)
@@ -139,4 +139,5 @@ void *silc_id_dup(void *id, SilcIdType type)
   int len = silc_id_get_len(type);
   void *new = silc_calloc(1, len);
   memcpy(new, id, len);
+  return new;
 }
index adf99a5875e3db1154b5e5b687ff68886907210a..d6e982633afc27aa6863fd4079ab39c870b3f799 100644 (file)
@@ -122,11 +122,12 @@ typedef unsigned short SilcCommandStatus;
 #define SILC_STATUS_ERR_UNKNOWN_MODE        37
 #define SILC_STATUS_ERR_NOT_YOU             38
 #define SILC_STATUS_ERR_NO_CHANNEL_PRIV     39
-#define SILC_STATUS_ERR_NO_SERVER_PRIV      40
-#define SILC_STATUS_ERR_NO_ROUTER_PRIV      41
-#define SILC_STATUS_ERR_BAD_NICKNAME        42
-#define SILC_STATUS_ERR_BAD_CHANNEL         43
-#define SILC_STATUS_ERR_AUTH_FAILED         44
+#define SILC_STATUS_ERR_NO_CHANNEL_FOPRIV   40
+#define SILC_STATUS_ERR_NO_SERVER_PRIV      41
+#define SILC_STATUS_ERR_NO_ROUTER_PRIV      42
+#define SILC_STATUS_ERR_BAD_NICKNAME        43
+#define SILC_STATUS_ERR_BAD_CHANNEL         44
+#define SILC_STATUS_ERR_AUTH_FAILED         45
 
 /* Prototypes */
 SilcCommandPayload silc_command_payload_parse(SilcBuffer buffer);
index 2cf198f5590c72d5b82bed4e08f1ac72eea67b46..8aa9d5800837eac6c1db50e92065b638a3c18ba5 100644 (file)
@@ -42,6 +42,7 @@ typedef unsigned short SilcNotifyType;
 #define SILC_NOTIFY_TYPE_MOTD            9 /* message of the day */
 #define SILC_NOTIFY_TYPE_CHANNEL_CHANGE  10 /* Channel's ID has changed */
 #define SILC_NOTIFY_TYPE_SERVER_SIGNOFF  11 /* Server quitting SILC */
+#define SILC_NOTIFY_TYPE_KICKED          12 /* Kicked from channel */
 
 /* Prototypes */
 SilcNotifyPayload silc_notify_payload_parse(SilcBuffer buffer);