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
 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.
 
                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 
        /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_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;
   }
   default:
     break;
   }
index b96c80d1e5f0259923bb7ad968dc6038692b1d14..58a76660ce2ce505aa1068140c5e6f19f591f818 100644 (file)
@@ -20,6 +20,9 @@
 /*
  * $Id$
  * $Log$
 /*
  * $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.
  *
  * Revision 1.5  2001/02/19 13:47:30  priikone
  *     updates.
  *
@@ -145,7 +148,8 @@ SILC_CLIENT_LCMD_FUNC(msg)
   }
 
   /* Find client entry */
   }
 
   /* 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. */
   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,
     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 {
        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,
       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;
       }
 
        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,
       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;
       }
 
        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,
       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;
       }
 
        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,
   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,
     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;
   }
 
     goto out;
   }
 
@@ -2818,6 +2818,151 @@ SILC_SERVER_CMD_FUNC(cumode)
 
 SILC_SERVER_CMD_FUNC(kick)
 {
 
 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)
 }
 
 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;
 
     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:
     /* 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);
 }
 
   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,
 /* 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 
 }
 
 /* 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
    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);
                                       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,
 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]
 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]
 
 [ListenPort]
-10.2.1.7:10.2.1.7:1334
+212.146.42.253:212.146.42.253:1334
 
 [Logging]
 infologfile:silcd2.log:10000
 
 [Logging]
 infologfile:silcd2.log:10000
@@ -43,10 +43,10 @@ errorlogfile:silcd2.log:10000
 [AdminConnection]
 
 [ServerConnection]
 [AdminConnection]
 
 [ServerConnection]
-10.2.1.7:passwd:priikone:1333:1:1
+212.146.42.253:passwd:priikone:1333:1:1
 
 [RouterConnection]
 
 [RouterConnection]
-10.2.1.7:passwd:priikone:1335:1:1:0
+212.146.42.253:passwd:priikone:1335:1:1:0
 
 [DenyConnection]
 [RedirectClient]
 
 [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
 
       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.
 
       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
 
       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.
 
       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
 
       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.
 
       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.
 
 
       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
 .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
    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
                         (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.
 
         "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.
 
 
         "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.
 
 
         "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.
 
 
         "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.
 
 
         "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.
 
         "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;
     /* 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;
     
   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(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",
   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 */
   }
 
   /* 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);
   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, 
 
   /* 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. */
   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;
 {
   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)
 }
 
 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(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" },
   { 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)
 {
 
 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)
 }
 
 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,
                                       SilcClientConnection conn,
                                       char *nickname,
                                       char *server,
-                                      unsigned int num)
+                                      unsigned int num,
+                                      int query)
 {
   SilcIDCacheEntry id_cache;
   SilcIDCacheList list = NULL;
 {
   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)) {
 
   /* Find ID from cache */
   if (!silc_idcache_find_by_data_loose(conn->client_cache, nickname, &list)) {
-    SilcClientCommandContext ctx;
-    char ident[512];
-    
   identify:
 
   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;
   }
 
     return NULL;
   }
 
index 543d745f2ac5a59204fccf13340422546e106771..4b831db68c91ade45424989c0853f90e9a86256a 100644 (file)
@@ -76,7 +76,8 @@ SilcClientEntry silc_idlist_get_client(SilcClient client,
                                       SilcClientConnection conn,
                                       char *nickname,
                                       char *server,
                                       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);
 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);
   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_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);
 
 /* 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_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);
 
 /* Prototypes */
 SilcNotifyPayload silc_notify_payload_parse(SilcBuffer buffer);