unsigned int arg_type,
unsigned char *arg,
unsigned int arg_len);
-void silc_server_command_send_users(SilcServer server,
- SilcSocketConnection sock,
- SilcChannelEntry channel,
- int pending);
+SILC_TASK_CALLBACK(silc_server_command_process_timeout);
/* Server command list. */
SilcServerCommand silc_command_list[] =
SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
- SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
- SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
+ SILC_SERVER_CMD(list, LIST, SILC_CF_LAG_STRICT | SILC_CF_REG),
SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
- SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+ SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG_STRICT | SILC_CF_REG | SILC_CF_OPER),
SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(connect, CONNECT,
SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
- SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG_STRICT | SILC_CF_REG),
SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
- SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
SILC_SERVER_CMD(restart, RESTART,
SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
SILC_SERVER_CMD(close, CLOSE,
SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
- SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+ SILC_SERVER_CMD(shutdown, SHUTDOWN, SILC_CF_LAG | SILC_CF_REG |
+ SILC_CF_OPER),
SILC_SERVER_CMD(silcoper, SILCOPER,
SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
- SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG),
SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
{ NULL, 0 },
return FALSE;
}
+/* Internal context to hold data when executed command with timeout. */
+typedef struct {
+ SilcServerCommandContext ctx;
+ SilcServerCommand *cmd;
+} *SilcServerCommandTimeout;
+
+/* Timeout callback to process commands with timeout for client. Client's
+ commands are always executed with timeout. */
+
+SILC_TASK_CALLBACK(silc_server_command_process_timeout)
+{
+ SilcServerCommandTimeout timeout = (SilcServerCommandTimeout)context;
+ SilcClientEntry client = (SilcClientEntry)timeout->ctx->sock->user_data;
+
+ /* Update access time */
+ client->last_command = time(NULL);
+
+ if (!(timeout->cmd->flags & SILC_CF_REG))
+ timeout->cmd->cb(timeout->ctx);
+ else if (silc_server_is_registered(timeout->ctx->server,
+ timeout->ctx->sock,
+ timeout->ctx,
+ timeout->cmd->cmd))
+ timeout->cmd->cb(timeout->ctx);
+
+ silc_free(timeout);
+}
+
/* Processes received command packet. */
void silc_server_command_process(SilcServer server,
SilcServerCommandContext ctx;
SilcServerCommand *cmd;
-#if 0
- /* XXX allow commands in but do not execute them more than once per
- two seconds. */
-
- /* Check whether it is allowed for this connection to execute any
- command. */
- if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
- time_t curtime;
- SilcClientEntry client = (SilcClientEntry)sock->user_data;
-
- if (!client)
- return;
-
- /* Allow only one command executed in 2 seconds. */
- curtime = time(NULL);
- if (client->last_command && (curtime - client->last_command) < 2)
- return;
-
- /* Update access time */
- client->last_command = curtime;
- }
-#endif
-
/* Allocate command context. This must be free'd by the
command routine receiving it. */
ctx = silc_server_command_alloc();
}
ctx->args = silc_command_get_args(ctx->payload);
- /* Execute command. If this fails the packet is dropped. */
+ /* Get the command */
for (cmd = silc_command_list; cmd->cb; cmd++)
- if (cmd->cmd == silc_command_get(ctx->payload)) {
-
- if (!(cmd->flags & SILC_CF_REG)) {
- cmd->cb(ctx);
- break;
- }
-
- if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
- cmd->cb(ctx);
- break;
- }
- }
+ if (cmd->cmd == silc_command_get(ctx->payload))
+ break;
if (cmd == NULL) {
SILC_LOG_ERROR(("Unknown command, packet dropped"));
silc_server_command_free(ctx);
return;
}
+
+ /* Execute client's commands always with timeout. Normally they are
+ executed with zero (0) timeout but if client is sending command more
+ frequently than once in 2 seconds, then the timeout may be 0 to 2
+ seconds. */
+ if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
+ SilcClientEntry client = (SilcClientEntry)sock->user_data;
+ SilcServerCommandTimeout timeout = silc_calloc(1, sizeof(*timeout));
+ int fast;
+
+ timeout->ctx = ctx;
+ timeout->cmd = cmd;
+
+ if (client->last_command && (time(NULL) - client->last_command) < 2) {
+ client->fast_command++;
+ fast = FALSE;
+ } else {
+ client->fast_command = ((client->fast_command - 1) <= 0 ? 0 :
+ client->fast_command--);
+ fast = TRUE;
+ }
+
+ if (!fast && ((cmd->flags & SILC_CF_LAG_STRICT) ||
+ (client->fast_command > 5 && cmd->flags & SILC_CF_LAG)))
+ silc_task_register(server->timeout_queue, sock->sock,
+ silc_server_command_process_timeout,
+ (void *)timeout,
+ 2 - (time(NULL) - client->last_command), 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ else
+ silc_task_register(server->timeout_queue, sock->sock,
+ silc_server_command_process_timeout,
+ (void *)timeout,
+ 0, 1,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ return;
+ }
+
+ /* Execute for server */
+
+ if (!(cmd->flags & SILC_CF_REG))
+ cmd->cb(ctx);
+ else if (silc_server_is_registered(server, sock, ctx, cmd->cmd))
+ cmd->cb(ctx);
}
/* Allocate Command Context */
*client_id_count = 1;
/* Take all ID's from the command packet */
- if (argc > 3) {
- for (k = 1, i = 4; i < argc + 1; i++) {
- tmp = silc_argument_get_arg_type(cmd->args, i, &len);
+ if (argc > 1) {
+ for (k = 1, i = 1; i < argc; i++) {
+ tmp = silc_argument_get_arg_type(cmd->args, i + 3, &len);
if (tmp) {
*client_id = silc_realloc(*client_id, sizeof(**client_id) *
(*client_id_count + 1));
for (i = 0; i < clients_count; i++) {
entry = clients[i];
+ if (entry->connection && entry->data.registered == FALSE) {
+ if (clients_count == 1)
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, entry->nickname,
+ strlen(entry->nickname));
+ continue;
+ }
+
if (count && i - 1 == count)
break;
idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
tmp = silc_argument_get_first_arg(cmd->args, NULL);
- /* XXX */
{
char nh[256], uh[256];
unsigned char idle[4];
SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
- /* XXX */
- if (entry->userinfo)
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
- status, ident, 5,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh),
- 4, uh, strlen(uh),
- 5, entry->userinfo,
- strlen(entry->userinfo),
- 7, idle, 4);
- else
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
- status, ident, 4,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh),
- 4, uh, strlen(uh),
- 7, idle, 4);
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
+ status, ident, 5,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh),
+ 4, uh, strlen(uh),
+ 5, entry->userinfo,
+ strlen(entry->userinfo),
+ 7, idle, 4);
}
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
clients = silc_idlist_get_clients_by_nickname(server->local_list,
nick, server_name,
&clients_count);
+ if (!clients)
+ clients = silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ &clients_count);
}
/* Check global list as well */
clients = silc_idlist_get_clients_by_nickname(server->global_list,
nick, server_name,
&clients_count);
+ if (!clients)
+ clients = silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ &clients_count);
}
}
silc_server_command_free(cmd);
}
+/******************************************************************************
+
+ WHOWAS Functions
+
+******************************************************************************/
+
+static int
+silc_server_command_whowas_parse(SilcServerCommandContext cmd,
+ char **nickname,
+ char **server_name,
+ int *count)
+{
+ unsigned char *tmp;
+ unsigned int len;
+
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOWAS,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return FALSE;
+ }
+
+ /* Get the nickname@server string and parse it. */
+ if (strchr(tmp, '@')) {
+ len = strcspn(tmp, "@");
+ *nickname = silc_calloc(len + 1, sizeof(char));
+ memcpy(*nickname, tmp, len);
+ *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
+ memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
+ } else {
+ *nickname = strdup(tmp);
+ }
+ /* Get the max count of reply messages allowed */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (tmp)
+ *count = atoi(tmp);
+ else
+ *count = 0;
+
+ return TRUE;
+}
+
+static void
+silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
+ SilcClientEntry *clients,
+ unsigned int clients_count)
+{
+ SilcServer server = cmd->server;
+ char *tmp;
+ int i, count = 0, len;
+ SilcBuffer packet, idp;
+ SilcClientEntry entry = NULL;
+ SilcCommandStatus status;
+ unsigned short ident = silc_command_get_ident(cmd->payload);
+ char found = FALSE;
+
+ status = SILC_STATUS_OK;
+ if (clients_count > 1)
+ status = SILC_STATUS_LIST_START;
+
+ for (i = 0; i < clients_count; i++) {
+ entry = clients[i];
+
+ /* We will take only clients that are not valid anymore. They are the
+ ones that are not registered anymore but still have a ID. They
+ have disconnected us, and thus valid for WHOWAS. */
+ if (entry->data.registered == TRUE)
+ continue;
+ if (entry->id == NULL)
+ continue;
+
+ if (count && i - 1 == count)
+ break;
+
+ found = TRUE;
+
+ if (clients_count > 2)
+ status = SILC_STATUS_LIST_ITEM;
+
+ if (clients_count > 1 && i == clients_count - 1)
+ status = SILC_STATUS_LIST_END;
+
+ /* Sanity check, however these should never fail. However, as
+ this sanity check has been added here they have failed. */
+ if (!entry->nickname || !entry->username)
+ continue;
+
+ /* Send WHOWAS reply */
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+ tmp = silc_argument_get_first_arg(cmd->args, NULL);
+
+ {
+ char nh[256], uh[256];
+
+ memset(uh, 0, sizeof(uh));
+ memset(nh, 0, sizeof(nh));
+
+ strncat(nh, entry->nickname, strlen(entry->nickname));
+ if (!strchr(entry->nickname, '@')) {
+ strncat(nh, "@", 1);
+ len = entry->router ? strlen(entry->router->server_name) :
+ strlen(server->server_name);
+ strncat(nh, entry->router ? entry->router->server_name :
+ server->server_name, len);
+ }
+
+ strncat(uh, entry->username, strlen(entry->username));
+ if (!strchr(entry->username, '@')) {
+ strncat(uh, "@", 1);
+ strcat(uh, "*private*");
+ }
+
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
+ status, ident, 4,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh),
+ 4, uh, strlen(uh),
+ 5, entry->userinfo,
+ strlen(entry->userinfo));
+ }
+
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+ 0, packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+ }
+
+ if (found == FALSE && entry)
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, entry->nickname,
+ strlen(entry->nickname));
+}
+
+static int
+silc_server_command_whowas_from_client(SilcServerCommandContext cmd)
+{
+ SilcServer server = cmd->server;
+ char *nick = NULL, *server_name = NULL;
+ int count = 0, clients_count = 0;
+ SilcClientEntry *clients = NULL;
+ int ret = 0;
+
+ /* Protocol dictates that we must always send the received WHOWAS request
+ to our router if we are normal server, so let's do it now unless we
+ are standalone. We will not send any replies to the client until we
+ have received reply from the router. */
+ if (server->server_type == SILC_SERVER &&
+ !cmd->pending && !server->standalone) {
+ SilcBuffer tmpbuf;
+ unsigned short old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ /* Send WHOWAS command to our router */
+ silc_server_packet_send(server, (SilcSocketConnection)
+ server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_WHOWAS,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_destructor,
+ silc_server_command_whois,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+
+ silc_command_set_ident(cmd->payload, old_ident);
+
+ silc_buffer_free(tmpbuf);
+ ret = -1;
+ goto out;
+ }
+
+ /* We are ready to process the command request. Let's search for the
+ requested client and send reply to the requesting client. */
+
+ /* Parse the whowas request */
+ if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
+ return 0;
+
+ /* Get all clients matching that nickname from local list */
+ clients = silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, server_name,
+ &clients_count);
+ if (!clients)
+ clients = silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ &clients_count);
+
+ /* Check global list as well */
+ if (!clients) {
+ clients = silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, server_name,
+ &clients_count);
+ if (!clients)
+ clients = silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ &clients_count);
+ }
+
+ if (!clients) {
+ /* Such client(s) really does not exist in the SILC network. */
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, nick, strlen(nick));
+ goto out;
+ }
+
+ /* Send the command reply to the client */
+ silc_server_command_whowas_send_reply(cmd, clients, clients_count);
+
+ out:
+ if (clients)
+ silc_free(clients);
+ if (nick)
+ silc_free(nick);
+ if (server_name)
+ silc_free(server_name);
+
+ return ret;
+}
+
+static int
+silc_server_command_whowas_from_server(SilcServerCommandContext cmd)
+{
+ SilcServer server = cmd->server;
+ char *nick = NULL, *server_name = NULL;
+ int count = 0, clients_count = 0;
+ SilcClientEntry *clients = NULL;
+ int ret = 0;
+
+ /* Parse the whowas request */
+ if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
+ return 0;
+
+ /* Process the command request. Let's search for the requested client and
+ send reply to the requesting server. */
+
+ clients = silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, server_name,
+ &clients_count);
+ if (!clients)
+ clients = silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ &clients_count);
+
+ /* If we are router we will check our global list as well. */
+ if (!clients && server->server_type == SILC_ROUTER) {
+ clients = silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, server_name,
+ &clients_count);
+ if (!clients)
+ clients = silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ &clients_count);
+ }
+
+ if (!clients) {
+ /* Such a client really does not exist in the SILC network. */
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, nick, strlen(nick));
+ goto out;
+ }
+
+ /* Send the command reply to the client */
+ silc_server_command_whowas_send_reply(cmd, clients, clients_count);
+
+ out:
+ if (clients)
+ silc_free(clients);
+ if (nick)
+ silc_free(nick);
+ if (server_name)
+ silc_free(server_name);
+
+ return ret;
+}
+
+/* Server side of command WHOWAS. */
+
SILC_SERVER_CMD_FUNC(whowas)
{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ int ret = 0;
+
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOWAS, cmd, 1, 2);
+
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ ret = silc_server_command_whowas_from_client(cmd);
+ else if ((cmd->sock->type == SILC_SOCKET_TYPE_SERVER) ||
+ (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER))
+ ret = silc_server_command_whowas_from_server(cmd);
+
+ if (!ret)
+ silc_server_command_free(cmd);
}
/******************************************************************************
for (i = 0; i < clients_count; i++) {
entry = clients[i];
+ if (entry->connection && entry->data.registered == FALSE) {
+ if (clients_count == 1)
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, entry->nickname,
+ strlen(entry->nickname));
+ continue;
+ }
+
if (count && i - 1 == count)
break;
if (!entry->username) {
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
- SILC_STATUS_OK, ident, 2,
+ status, ident, 2,
2, idp->data, idp->len,
3, nh, strlen(nh));
} else {
}
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
- SILC_STATUS_OK, ident, 3,
+ status, ident, 3,
2, idp->data, idp->len,
3, nh, strlen(nh),
4, uh, strlen(uh));
clients = silc_idlist_get_clients_by_nickname(server->local_list,
nick, server_name,
&clients_count);
+ if (!clients)
+ clients = silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ &clients_count);
}
/* Check global list as well */
clients = silc_idlist_get_clients_by_nickname(server->global_list,
nick, server_name,
&clients_count);
+ if (!clients)
+ clients = silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ &clients_count);
}
}
SilcClientID *new_id;
char *nick;
+ if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_NICK, cmd, 1, 1);
/* Check nickname */
goto out;
}
+ if (strlen(nick) > 128)
+ nick[127] = '\0';
+
/* Create new Client ID */
silc_id_create_client_id(cmd->server->id, cmd->server->rng,
cmd->server->md5hash, nick,
/* Send notify about nickname change to our router. We send the new
ID and ask to replace it with the old one. If we are router the
- packet is broadcasted. */
+ packet is broadcasted. Send NICK_CHANGE notify. */
if (!server->standalone)
- silc_server_send_replace_id(server, server->router->connection,
- server->server_type == SILC_SERVER ?
- FALSE : TRUE, client->id,
- SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
- new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
+ silc_server_send_notify_nick_change(server, server->router->connection,
+ server->server_type == SILC_SERVER ?
+ FALSE : TRUE, client->id,
+ new_id, SILC_ID_CLIENT_LEN);
/* Remove old cache entry */
silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT,
/* Update client cache */
silc_idcache_add(server->local_list->clients, client->nickname,
- SILC_ID_CLIENT, client->id, (void *)client, TRUE);
+ SILC_ID_CLIENT, client->id, (void *)client, TRUE, FALSE);
nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
- /* Send NICK_CHANGE notify */
+ /* Send NICK_CHANGE notify to the client's channels */
silc_server_send_notify_on_channels(server, client,
SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
oidp->data, oidp->len,
channel = silc_idlist_find_channel_by_id(server->local_list,
channel_id, NULL);
if (!channel) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL);
- goto out;
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
}
if (argc > 1) {
silc_free(channel->topic);
channel->topic = strdup(tmp);
+ /* Send TOPIC_SET notify type to the network */
+ if (!server->standalone)
+ silc_server_send_notify_topic_set(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel, client->id,
+ SILC_ID_CLIENT_LEN, channel->topic);
+
idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
/* Send notify about topic change to all clients on the channel */
channel = silc_idlist_find_channel_by_id(server->local_list,
channel_id, NULL);
if (!channel) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL);
- goto out;
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
}
/* Check whether the sender of this command is on the channel. */
sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
/* Send notify to the client that is invited to the channel */
- silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
+ silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id,
+ SILC_ID_CLIENT,
SILC_NOTIFY_TYPE_INVITE, 2,
sidp->data, sidp->len, tmp, len);
silc_server_command_free(cmd);
}
+typedef struct {
+ SilcServer server;
+ SilcSocketConnection sock;
+ char *signoff;
+} *QuitInternal;
+
/* Quits connection to client. This gets called if client won't
close the connection even when it has issued QUIT command. */
SILC_TASK_CALLBACK(silc_server_command_quit_cb)
{
- SilcServer server = (SilcServer)context;
- SilcSocketConnection sock = server->sockets[fd];
+ QuitInternal q = (QuitInternal)context;
/* Free all client specific data, such as client entry and entires
on channels this client may be on. */
- silc_server_free_sock_user_data(server, sock);
+ silc_server_free_client_data(q->server, q->sock, q->sock->user_data,
+ q->signoff);
+ q->sock->user_data = NULL;
/* Close the connection on our side */
- silc_server_close_connection(server, sock);
+ silc_server_close_connection(q->server, q->sock);
+
+ silc_free(q->signoff);
+ silc_free(q);
}
/* Quits SILC session. This is the normal way to disconnect client. */
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcSocketConnection sock = cmd->sock;
+ QuitInternal q;
+ unsigned char *tmp = NULL;
+ unsigned int len = 0;
- SILC_LOG_DEBUG(("Start"));
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_QUIT, cmd, 0, 1);
+
+ if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ /* Get destination ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+ if (len > 128)
+ tmp = NULL;
+
+ q = silc_calloc(1, sizeof(*q));
+ q->server = server;
+ q->sock = sock;
+ q->signoff = tmp ? strdup(tmp) : NULL;
/* We quit the connection with little timeout */
silc_task_register(server->timeout_queue, sock->sock,
- silc_server_command_quit_cb, server,
- 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ silc_server_command_quit_cb, (void *)q,
+ 0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ out:
silc_server_command_free(cmd);
}
silc_server_command_free(cmd);
}
-SILC_SERVER_CMD_FUNC(connect)
-{
-}
-
/* Server side of command PING. This just replies to the ping. */
SILC_SERVER_CMD_FUNC(ping)
goto out;
if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
- /* Send our reply */
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
- SILC_STATUS_OK);
- } else {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
- SILC_STATUS_ERR_NO_SUCH_SERVER);
- goto out;
- }
-
- silc_free(id);
-
- out:
- silc_server_command_free(cmd);
-}
-
-SILC_SERVER_CMD_FUNC(oper)
-{
-}
-
-/* Assembles USERS command and executes it. This is called when client
- joins to a channel and we wan't to send USERS command reply to the
- client. */
-
-void silc_server_command_send_users(SilcServer server,
- SilcSocketConnection sock,
- SilcChannelEntry channel,
- int pending)
-{
- SilcServerCommandContext cmd;
- SilcBuffer buffer, idp;
- SilcPacketContext *packet = silc_packet_context_alloc();
-
- SILC_LOG_DEBUG(("Start"));
-
- /* Create USERS command packet and process it. */
- idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
- buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, 0, 1,
- 1, idp->data, idp->len);
-
- packet->buffer = silc_buffer_copy(buffer);
- packet->sock = sock;
- packet->type = SILC_PACKET_COMMAND;
-
- cmd = silc_server_command_alloc();
- cmd->payload = silc_command_payload_parse(buffer);
- if (!cmd->payload) {
- silc_free(cmd);
- silc_buffer_free(buffer);
- silc_buffer_free(idp);
- silc_packet_context_free(packet);
- return;
- }
- cmd->args = silc_command_get_args(cmd->payload);
- cmd->server = server;
- cmd->sock = silc_socket_dup(sock);
- cmd->packet = silc_packet_context_dup(packet);
- cmd->pending = FALSE;
-
- if (pending) {
- /* If this function was called from pending command then instead of
- processing the command now, register a pending command callback which
- will process it after we've received the automatic USERS command
- reply which server will send in JOIN. */
- silc_server_command_pending(server, SILC_COMMAND_USERS, 0, NULL,
- silc_server_command_users, cmd);
- cmd->pending = TRUE;
- silc_buffer_free(buffer);
- silc_buffer_free(idp);
- return;
+ /* Send our reply */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
+ SILC_STATUS_OK);
+ } else {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
+ SILC_STATUS_ERR_NO_SUCH_SERVER);
+ goto out;
}
- /* Process USERS command. */
- silc_server_command_users((void *)cmd);
+ silc_free(id);
- silc_buffer_free(buffer);
- silc_buffer_free(idp);
- silc_packet_context_free(packet);
+ out:
+ silc_server_command_free(cmd);
}
/* Internal routine to join channel. The channel sent to this function
{
SilcSocketConnection sock = cmd->sock;
unsigned char *tmp;
- unsigned int tmp_len;
- unsigned char *passphrase = NULL, mode[4], tmp2[4];
+ unsigned int tmp_len, user_count;
+ unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4];
SilcClientEntry client;
SilcChannelClientEntry chl;
- SilcBuffer reply, chidp, clidp, keyp;
+ SilcBuffer reply, chidp, clidp, keyp, user_list, mode_list;
unsigned short ident = silc_command_get_ident(cmd->payload);
SILC_LOG_DEBUG(("Start"));
}
/* Generate new channel key as protocol dictates */
- if (!created || !channel->channel_key)
+ if ((!created && silc_list_count(channel->user_list) > 0) ||
+ !channel->channel_key)
silc_server_create_channel_key(server, channel, 0);
/* Send the channel key. This is broadcasted to the channel but is not
sent to the client who is joining to the channel. */
silc_server_send_channel_key(server, NULL, channel,
server->server_type == SILC_ROUTER ?
- FALSE : server->standalone);
+ FALSE : !server->standalone);
/* Join the client to the channel by adding it to channel's user list.
Add also the channel to client entry's channels list for fast cross-
silc_list_add(channel->user_list, chl);
silc_list_add(client->channels, chl);
+ /* Get users on the channel */
+ silc_server_get_users_on_channel(server, channel, &user_list, &mode_list,
+ &user_count);
+
/* Encode Client ID Payload of the original client who wants to join */
clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
SILC_PUT32_MSB(channel->mode, mode);
SILC_PUT32_MSB(created, tmp2);
+ SILC_PUT32_MSB(user_count, tmp3);
tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
keyp = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp,
- SILC_ID_CHANNEL_LEN,
+ strlen(channel->channel_key->
+ cipher->name),
channel->channel_key->cipher->name,
channel->key_len / 8, channel->key);
silc_free(tmp);
if (!channel->topic) {
reply =
silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
- SILC_STATUS_OK, ident, 5,
+ SILC_STATUS_OK, ident, 9,
2, channel->channel_name,
strlen(channel->channel_name),
3, chidp->data, chidp->len,
- 4, mode, 4,
- 5, tmp2, 4,
- 6, keyp->data, keyp->len);
+ 4, clidp->data, clidp->len,
+ 5, mode, 4,
+ 6, tmp2, 4,
+ 7, keyp->data, keyp->len,
+ 12, tmp3, 4,
+ 13, user_list->data, user_list->len,
+ 14, mode_list->data,
+ mode_list->len);
} else {
reply =
silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
- SILC_STATUS_OK, ident, 6,
+ SILC_STATUS_OK, ident, 10,
2, channel->channel_name,
strlen(channel->channel_name),
3, chidp->data, chidp->len,
- 4, mode, 4,
- 5, tmp2, 4,
- 6, keyp->data, keyp->len,
- 8, channel->topic,
- strlen(channel->topic));
+ 4, clidp->data, clidp->len,
+ 5, mode, 4,
+ 6, tmp2, 4,
+ 7, keyp->data, keyp->len,
+ 10, channel->topic,
+ strlen(channel->topic),
+ 12, tmp3, 4,
+ 13, user_list->data, user_list->len,
+ 14, mode_list->data,
+ mode_list->len);
}
/* Send command reply */
if (!cmd->pending) {
/* Send JOIN notify to locally connected clients on the channel */
silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_JOIN, 1,
- clidp->data, clidp->len);
+ SILC_NOTIFY_TYPE_JOIN, 2,
+ clidp->data, clidp->len,
+ chidp->data, chidp->len);
- /* Send NEW_CHANNEL_USER packet to our primary router */
+ /* Send JOIN notify packet to our primary router */
if (!server->standalone)
- silc_server_send_new_channel_user(server, server->router->connection,
- server->server_type == SILC_SERVER ?
- FALSE : TRUE,
- channel->id, SILC_ID_CHANNEL_LEN,
- client->id, SILC_ID_CLIENT_LEN);
+ silc_server_send_notify_join(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel, client->id,
+ SILC_ID_CLIENT_LEN);
}
- /* Send USERS command reply to the joined channel so the user sees who
- is currently on the channel. */
- silc_server_command_send_users(server, sock, channel, cmd->pending);
-
silc_buffer_free(reply);
silc_buffer_free(clidp);
silc_buffer_free(chidp);
silc_buffer_free(keyp);
+ silc_buffer_free(user_list);
+ silc_buffer_free(mode_list);
out:
if (passphrase)
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
int tmp_len;
- char *tmp, *channel_name = NULL, *cipher = NULL;
+ char *tmp, *channel_name = NULL, *cipher, *hmac;
SilcChannelEntry channel;
unsigned int umode = 0;
int created = FALSE;
}
channel_name = tmp;
+ if (strlen(channel_name) > 256)
+ channel_name[255] = '\0';
+
if (silc_server_command_bad_chars(channel_name) == TRUE) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
SILC_STATUS_ERR_BAD_CHANNEL);
goto out;
}
- /* Get cipher name */
+ /* Get cipher and hmac name */
cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
+ hmac = silc_argument_get_arg_type(cmd->args, 5, NULL);
/* See if the channel exists */
channel = silc_idlist_find_channel_by_name(server->local_list,
the channel by ourselves. */
if (server->standalone) {
channel = silc_server_create_new_channel(server, server->id, cipher,
- channel_name, TRUE);
+ hmac, channel_name, TRUE);
umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
created = TRUE;
if (!channel) {
/* Channel really does not exist, create it */
channel = silc_server_create_new_channel(server, server->id, cipher,
- channel_name, TRUE);
+ hmac, channel_name, TRUE);
umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
created = TRUE;
}
if (!channel) {
/* Channel really does not exist, create it */
channel = silc_server_create_new_channel(server, server->id, cipher,
- channel_name, TRUE);
+ hmac, channel_name, TRUE);
umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
created = TRUE;
}
channel = silc_idlist_find_channel_by_id(server->local_list,
channel_id, NULL);
if (!channel) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL);
- goto out;
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
}
/* Check whether this client is on the channel */
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 {
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;
}
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;
}
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;
}
if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
/* Cipher to use protect the traffic */
- unsigned int key_len = 128;
- char *cp;
+ unsigned int key_len;
/* Get cipher */
tmp = silc_argument_get_arg_type(cmd->args, 8, 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;
}
- cp = strchr(tmp, ':');
- if (cp) {
- key_len = atoi(cp);
- *cp = '\0';
- }
-
/* XXX Duplicated code, make own function for this!! */
/* Delete old cipher and allocate the new one */
silc_cipher_free(channel->channel_key);
- silc_cipher_alloc(tmp, &channel->channel_key);
-
- key_len /= 8;
- if (key_len > 32)
- key_len = 32;
+ if (!silc_cipher_alloc(tmp, &channel->channel_key)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ goto out;
+ }
+ key_len = silc_cipher_get_key_len(channel->channel_key) / 8;
/* Re-generate channel key */
silc_server_create_channel_key(server, channel, key_len);
/* Delete old cipher and allocate default one */
silc_cipher_free(channel->channel_key);
if (!channel->cipher)
- silc_cipher_alloc("twofish", &channel->channel_key);
- else
- silc_cipher_alloc(channel->cipher, &channel->channel_key);
+ silc_cipher_alloc("aes-256-cbc", &channel->channel_key);
+ else {
+ if (!silc_cipher_alloc(channel->cipher, &channel->channel_key)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ goto out;
+ }
+ }
/* Re-generate channel key */
silc_server_create_channel_key(server, channel, 0);
/* Send CMODE_CHANGE notify */
cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
- silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
cidp->data, cidp->len,
tmp_mask, tmp_len);
- /* Set SET_MODE packet to network */
+ /* Set CMODE notify type to network */
if (!server->standalone)
- silc_server_send_set_mode(server, server->router->connection,
- server->server_type == SILC_ROUTER ?
- TRUE : FALSE, SILC_MODE_TYPE_CHANNEL,
- mode_mask, 2,
- tmp_id, tmp_len2,
- cidp->data, cidp->len);
+ silc_server_send_notify_cmode(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel,
+ mode_mask, client->id, SILC_ID_CLIENT_LEN);
/* Send command reply to sender */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
channel = silc_idlist_find_channel_by_id(server->local_list,
channel_id, NULL);
if (!channel) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL);
- goto out;
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
}
/* Check whether sender is on the channel */
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;
}
/* Send notify to channel, notify only if mode was actually changed. */
if (notify) {
- silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
idp->data, idp->len,
tmp_mask, 4,
tmp_id, tmp_len);
- }
- /* Set SET_MODE packet to network */
- if (!server->standalone)
- silc_server_send_set_mode(server, server->router->connection,
- server->server_type == SILC_ROUTER ?
- TRUE : FALSE, SILC_MODE_TYPE_UCHANNEL,
- target_mask, 3,
- tmp_ch_id, tmp_ch_len,
- idp->data, idp->len,
- tmp_id, tmp_len);
+ /* Set CUMODE notify type to network */
+ if (!server->standalone)
+ silc_server_send_notify_cumode(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel,
+ target_mask, client->id,
+ SILC_ID_CLIENT_LEN,
+ target_client->id,
+ SILC_ID_CLIENT_LEN);
+ }
/* Send command reply to sender */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_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) {
+ 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(oper)
+{
+}
+
+SILC_SERVER_CMD_FUNC(silcoper)
+{
+}
+
+/* Server side command of CONNECT. Connects us to the specified remote
+ server or router. */
+
+SILC_SERVER_CMD_FUNC(connect)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ unsigned char *tmp;
+ unsigned int tmp_len;
+ unsigned int port = SILC_PORT;
+
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CONNECT, cmd, 1, 2);
+
+ if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ /* Check whether client has the permissions. */
+ if (client->mode == SILC_UMODE_NONE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
+ SILC_STATUS_ERR_NO_SERVER_PRIV);
+ goto out;
+ }
+
+ if (server->server_type == SILC_ROUTER &&
+ client->mode & SILC_UMODE_SERVER_OPERATOR) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
+ SILC_STATUS_ERR_NO_ROUTER_PRIV);
+ goto out;
+ }
+
+ /* Get the remote server */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Get port */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (tmp)
+ SILC_GET32_MSB(port, tmp);
+
+ /* Create the connection. It is done with timeout and is async. */
+ silc_server_create_connection(server, tmp, port);
+
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
+ SILC_STATUS_OK);
+
+ out:
+ silc_server_command_free(cmd);
}
SILC_SERVER_CMD_FUNC(restart)
{
}
+
+/* Server side command of CLOSE. Closes connection to a specified server. */
SILC_SERVER_CMD_FUNC(close)
{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcServerEntry server_entry;
+ unsigned char *tmp;
+ unsigned int tmp_len;
+ unsigned char *name;
+ unsigned int port = SILC_PORT;
+
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CLOSE, cmd, 1, 2);
+
+ if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ /* Check whether client has the permissions. */
+ if (client->mode == SILC_UMODE_NONE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
+ SILC_STATUS_ERR_NO_SERVER_PRIV);
+ goto out;
+ }
+
+ /* Get the remote server */
+ name = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!name) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Get port */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (tmp)
+ SILC_GET32_MSB(port, tmp);
+
+ server_entry = silc_idlist_find_server_by_conn(server->local_list,
+ name, port, NULL);
+ if (!server_entry) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
+ SILC_STATUS_ERR_NO_SERVER_ID);
+ goto out;
+ }
+
+ /* Close the connection to the server */
+ silc_server_free_sock_user_data(server, server_entry->connection);
+ silc_server_disconnect_remote(server, server_entry->connection,
+ "Server closed connection: "
+ "Closed by operator");
+
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
+ SILC_STATUS_OK);
+
+ out:
+ silc_server_command_free(cmd);
}
+
+/* Server side command of SHUTDOWN. Shutdowns the server and closes all
+ active connections. */
-SILC_SERVER_CMD_FUNC(die)
+SILC_SERVER_CMD_FUNC(shutdown)
{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SHUTDOWN, cmd, 0, 0);
+
+ if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ /* Check whether client has the permission. */
+ if (client->mode == SILC_UMODE_NONE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
+ SILC_STATUS_ERR_NO_SERVER_PRIV);
+ goto out;
+ }
+
+ /* Then, gracefully, or not, bring the server down. */
+ silc_server_stop(server);
+
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
+ SILC_STATUS_OK);
+
+ out:
+ silc_server_command_free(cmd);
}
-SILC_SERVER_CMD_FUNC(silcoper)
-{
-}
-
/* Server side command of LEAVE. Removes client from a channel. */
SILC_SERVER_CMD_FUNC(leave)
/* Get channel entry */
channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
if (!channel) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL);
- goto out;
+ channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
}
/* Check whether this client is on the channel */
}
/* Notify routers that they should remove this client from their list
- of clients on the channel. */
+ of clients on the channel. Send LEAVE notify type. */
if (!server->standalone)
- silc_server_send_remove_channel_user(server,
- server->router->connection,
- server->server_type == SILC_ROUTER ?
- TRUE : FALSE, id_entry->id, id);
+ silc_server_send_notify_leave(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel, id_entry->id,
+ SILC_ID_CLIENT_LEN);
/* Remove client from channel */
i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcChannelEntry channel;
- SilcChannelClientEntry chl;
SilcChannelID *id;
SilcBuffer packet;
unsigned char *channel_id;
unsigned int channel_id_len;
SilcBuffer client_id_list;
SilcBuffer client_mode_list;
- SilcBuffer idp;
unsigned char lc[4];
unsigned int list_count = 0;
unsigned short ident = silc_command_get_ident(cmd->payload);
}
}
- /* Assemble the lists now */
-
- client_id_list = silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) *
- silc_list_count(channel->user_list));
- silc_buffer_pull_tail(client_id_list, SILC_BUFFER_END(client_id_list));
- client_mode_list =
- silc_buffer_alloc(4 * silc_list_count(channel->user_list));
- silc_buffer_pull_tail(client_mode_list, SILC_BUFFER_END(client_mode_list));
-
- silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
- /* Client ID */
- idp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
- silc_buffer_put(client_id_list, idp->data, idp->len);
- silc_buffer_pull(client_id_list, idp->len);
- silc_buffer_free(idp);
-
- /* Client's mode on channel */
- SILC_PUT32_MSB(chl->mode, client_mode_list->data);
- silc_buffer_pull(client_mode_list, 4);
-
- list_count++;
- }
- silc_buffer_push(client_id_list,
- client_id_list->data - client_id_list->head);
- silc_buffer_push(client_mode_list,
- client_mode_list->data - client_mode_list->head);
+ /* Get the users list */
+ silc_server_get_users_on_channel(server, channel, &client_id_list,
+ &client_mode_list, &list_count);
/* List count */
SILC_PUT32_MSB(list_count, lc);