From: Pekka Riikonen Date: Sat, 24 Feb 2001 15:50:23 +0000 (+0000) Subject: implemented KICK command X-Git-Tag: SILC.0.1~174 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=0dcbb205044702fc7aa8563ef164328a218c4e69 implemented KICK command --- diff --git a/CHANGES b/CHANGES index 23617be1..da495f1f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,23 @@ +Sat Feb 24 16:03:45 EET 2001 Pekka Riikonen + + * 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 * Removed the rng context from SilcPacketContext structure and diff --git a/README b/README index f37377ac..e25a8451 100644 --- 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 [@] [] + + 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 [] Pings server. Only locally connected server may be diff --git a/apps/silc/client_ops.c b/apps/silc/client_ops.c index 830c6e90..48ba1152 100644 --- a/apps/silc/client_ops.c +++ b/apps/silc/client_ops.c @@ -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; } diff --git a/apps/silc/local_command.c b/apps/silc/local_command.c index b96c80d1..58a76660 100644 --- a/apps/silc/local_command.c +++ b/apps/silc/local_command.c @@ -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. */ diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 188c04ca..05c385d6 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -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) diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 3c66a912..16ae24db 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -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: diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index 4bebe183..b8c720c6 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -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 diff --git a/apps/silcd/packet_send.h b/apps/silcd/packet_send.h index 827e609c..87b072f6 100644 --- a/apps/silcd/packet_send.h +++ b/apps/silcd/packet_send.h @@ -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, diff --git a/apps/silcd/testi2.conf b/apps/silcd/testi2.conf index fe6247a1..0ece9ca0 100644 --- a/apps/silcd/testi2.conf +++ b/apps/silcd/testi2.conf @@ -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] diff --git a/doc/draft-riikonen-silc-pp-01.nroff b/doc/draft-riikonen-silc-pp-01.nroff index 30d1be15..7a87af28 100644 --- a/doc/draft-riikonen-silc-pp-01.nroff +++ b/doc/draft-riikonen-silc-pp-01.nroff @@ -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 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) (2) [] + + The is the client who was kicked from the channel. + The kicker may have set the to indicate the reason for + the kicking. + .in 3 Notify types starting from 16384 are reserved for private notify diff --git a/doc/draft-riikonen-silc-spec-01.nroff b/doc/draft-riikonen-silc-spec-01.nroff index 08806957..7e9c35cb 100644 --- a/doc/draft-riikonen-silc-spec-01.nroff +++ b/doc/draft-riikonen-silc-spec-01.nroff @@ -2804,7 +2804,7 @@ List of all defined commands in SILC follows. 19 SILC_COMMAND_KICK Max Arguments: 3 - Arguments: (1) (2) + Arguments: (1) (2) (3) [] 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. diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index f44ea4e8..8447ee3c 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -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; diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index 594b13f2..8a3e6910 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -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 []"); + 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) diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index 2c576730..c026a869 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -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) diff --git a/lib/silcclient/idlist.c b/lib/silcclient/idlist.c index 8da74caf..0236c812 100644 --- a/lib/silcclient/idlist.c +++ b/lib/silcclient/idlist.c @@ -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; } diff --git a/lib/silcclient/idlist.h b/lib/silcclient/idlist.h index 543d745f..4b831db6 100644 --- a/lib/silcclient/idlist.h +++ b/lib/silcclient/idlist.h @@ -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); diff --git a/lib/silccore/id.c b/lib/silccore/id.c index 51e69bad..7cb854fc 100644 --- a/lib/silccore/id.c +++ b/lib/silccore/id.c @@ -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; } diff --git a/lib/silccore/silccommand.h b/lib/silccore/silccommand.h index adf99a58..d6e98263 100644 --- a/lib/silccore/silccommand.h +++ b/lib/silccore/silccommand.h @@ -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); diff --git a/lib/silccore/silcnotify.h b/lib/silccore/silcnotify.h index 2cf198f5..8aa9d580 100644 --- a/lib/silccore/silcnotify.h +++ b/lib/silccore/silcnotify.h @@ -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);