Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
- Copyright (C) 1997 - 2000 Pekka Riikonen
+ Copyright (C) 1997 - 2001 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
unsigned char *arg,
unsigned int arg_len);
static void silc_server_command_free(SilcServerCommandContext cmd);
-void silc_server_command_send_names(SilcServer server,
+void silc_server_command_send_users(SilcServer server,
SilcSocketConnection sock,
- SilcChannelEntry channel);
+ SilcChannelEntry channel,
+ int pending);
/* Server command list. */
SilcServerCommand silc_command_list[] =
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(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
{ NULL, 0 },
};
+#define SILC_SERVER_COMMAND_CHECK_ARGC(command, context, min, max) \
+do { \
+ unsigned int _argc = silc_argument_get_arg_num(cmd->args); \
+ \
+ SILC_LOG_DEBUG(("Start")); \
+ \
+ if (_argc < min) { \
+ silc_server_command_send_status_reply(cmd, command, \
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
+ silc_server_command_free(cmd); \
+ return; \
+ } \
+ if (_argc > max) { \
+ silc_server_command_send_status_reply(cmd, command, \
+ SILC_STATUS_ERR_TOO_MANY_PARAMS); \
+ silc_server_command_free(cmd); \
+ return; \
+ } \
+} while(0)
+
/* Returns TRUE if the connection is registered. Unregistered connections
usually cannot send commands hence the check. */
silc_buffer_free(buffer);
}
-/* Server side of command WHOIS. Processes user's query and sends found
- results as command replies back to the client. */
+/******************************************************************************
-SILC_SERVER_CMD_FUNC(whois)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- char *tmp, *nick = NULL, *server_name = NULL;
- unsigned int i, argc, count = 0, len, clients_count;
- int use_id = FALSE;
- SilcClientID *client_id = NULL;
- SilcBuffer packet, idp;
- SilcClientEntry *clients = NULL, entry;
- SilcCommandStatus status;
+ WHOIS Functions
- SILC_LOG_DEBUG(("Start"));
+******************************************************************************/
- argc = silc_argument_get_arg_num(cmd->args);
- if (argc < 1) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- if (argc > 3) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
- goto out;
- }
+static int
+silc_server_command_whois_parse(SilcServerCommandContext cmd,
+ SilcClientID ***client_id,
+ unsigned int *client_id_count,
+ char **nickname,
+ char **server_name,
+ int *count,
+ SilcCommand command)
+{
+ unsigned char *tmp;
+ unsigned int len;
+ unsigned int argc = silc_argument_get_arg_num(cmd->args);
+ int i, k;
/* If client ID is in the command it must be used instead of nickname */
- tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
if (!tmp) {
-
/* No ID, get the nickname@server string and parse it. */
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
if (tmp) {
if (strchr(tmp, '@')) {
len = strcspn(tmp, "@");
- nick = silc_calloc(len + 1, sizeof(char));
- memcpy(nick, tmp, len);
- server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
- memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
+ *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 {
- nick = strdup(tmp);
+ *nickname = strdup(tmp);
}
} else {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
+ silc_server_command_send_status_reply(cmd, command,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
+ return FALSE;
}
} else {
+ /* Command includes ID, we must use that. Also check whether the command
+ has more than one ID set - take them all. */
+
+ *client_id = silc_calloc(1, sizeof(**client_id));
+ (*client_id)[0] = silc_id_payload_parse_id(tmp, len);
+ if ((*client_id)[0] == NULL) {
+ silc_free(*client_id);
+ return FALSE;
+ }
+ *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 (tmp) {
+ *client_id = silc_realloc(*client_id, sizeof(**client_id) *
+ (*client_id_count + 1));
+ (*client_id)[k] = silc_id_payload_parse_id(tmp, len);
+ if ((*client_id)[k] == NULL) {
+ /* Cleanup all and fail */
+ for (i = 0; i < *client_id_count; i++)
+ silc_free((*client_id)[i]);
+ silc_free(*client_id);
+ return FALSE;
+ }
+ (*client_id_count)++;
+ k++;
+ }
+ }
+ }
+
/* Command includes ID, use that */
- client_id = silc_id_payload_parse_id(tmp, len);
- use_id = TRUE;
}
/* Get the max count of reply messages allowed */
- if (argc == 3) {
- tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
- if (!tmp) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
- if (nick)
- silc_free(nick);
- if (server_name)
- silc_free(server_name);
- goto out;
- }
- count = atoi(tmp);
- }
+ tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (tmp)
+ *count = atoi(tmp);
+ else
+ *count = 0;
- /* Protocol dictates that we must always send the received WHOIS 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->standalone) {
- SilcBuffer tmpbuf;
+ return TRUE;
+}
- silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+static char
+silc_server_command_whois_check(SilcServerCommandContext cmd,
+ SilcClientEntry *clients,
+ unsigned int clients_count)
+{
+ SilcServer server = cmd->server;
+ int i;
+ SilcClientEntry entry;
- /* Send WHOIS command to our router */
- silc_server_packet_send(server, (SilcSocketConnection)
- server->router->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
- return;
- } else {
- /* We are standalone, let's just do local search and send reply to
- requesting client. */
+ for (i = 0; i < clients_count; i++) {
+ entry = clients[i];
- /* Get all clients matching that nickname */
- if (!use_id) {
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
- } else {
- entry = silc_idlist_find_client_by_id(server->local_list, client_id);
- if (entry) {
- clients = silc_calloc(1, sizeof(*clients));
- clients[0] = entry;
- clients_count = 1;
- }
- }
-
- /* If we are router then we will check our global list as well. */
- if (server->server_type == SILC_ROUTER) {
- entry =
- silc_idlist_find_client_by_nickname(server->global_list,
- nick, server_name);
- if (!entry) {
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, tmp, strlen(tmp));
- goto out;
- }
- goto ok;
- }
+ if (!entry->nickname || !entry->username) {
+ SilcBuffer tmpbuf;
+ unsigned short old_ident;
+
+ if (!entry->router)
+ continue;
-#if 0
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, tmp, strlen(tmp));
- goto out;
-#endif
+ 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 WHOIS command */
+ silc_server_packet_send(server, entry->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply */
+ silc_server_command_pending(server, SILC_COMMAND_WHOIS,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_whois, (void *)cmd);
+ cmd->pending = TRUE;
+
+ silc_command_set_ident(cmd->payload, old_ident);
+
+ silc_buffer_free(tmpbuf);
+ return FALSE;
+ }
}
- /* We are standalone and will send reply to client */
- ok:
-
+ return TRUE;
+}
+
+static void
+silc_server_command_whois_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;
+ SilcCommandStatus status;
+ unsigned short ident = silc_command_get_ident(cmd->payload);
+
status = SILC_STATUS_OK;
if (clients_count > 1)
status = SILC_STATUS_LIST_START;
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 WHOIS reply */
idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
tmp = silc_argument_get_first_arg(cmd->args, NULL);
/* XXX */
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+ {
char nh[256], uh[256];
unsigned char idle[4];
SilcSocketConnection hsock;
memset(uh, 0, sizeof(uh));
memset(nh, 0, sizeof(nh));
-
+
strncat(nh, entry->nickname, strlen(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);
+ 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));
- strncat(uh, "@", 1);
- hsock = (SilcSocketConnection)entry->connection;
- len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
- strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
+ if (!strchr(entry->username, '@')) {
+ strncat(uh, "@", 1);
+ hsock = (SilcSocketConnection)entry->connection;
+ len = strlen(hsock->hostname);
+ strncat(uh, hsock->hostname, len);
+ }
SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
if (entry->userinfo)
packet =
silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
- status, 0, 5,
+ status, ident, 5,
2, idp->data, idp->len,
3, nh, strlen(nh),
4, uh, strlen(uh),
else
packet =
silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
- status, 0, 4,
+ status, ident, 4,
2, idp->data, idp->len,
3, nh, strlen(nh),
4, uh, strlen(uh),
7, idle, 4);
-
- } else {
- /* XXX */
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
- status, 0, 3,
- 2, idp->data, idp->len,
- 3, entry->nickname,
- strlen(entry->nickname),
- 4, tmp, strlen(tmp)); /* XXX */
}
+
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);
}
+}
+
+static int
+silc_server_command_whois_from_client(SilcServerCommandContext cmd)
+{
+ SilcServer server = cmd->server;
+ char *nick = NULL, *server_name = NULL;
+ int count = 0, clients_count = 0;
+ SilcClientEntry *clients = NULL, entry;
+ SilcClientID **client_id = NULL;
+ unsigned int client_id_count = 0;
+ int i, ret = 0;
+
+ /* Protocol dictates that we must always send the received WHOIS 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 WHOIS 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_WHOIS,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_whois, (void *)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 whois request */
+ if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
+ &nick, &server_name, &count,
+ SILC_COMMAND_WHOIS))
+ return 0;
+
+ /* Get all clients matching that ID or nickname from local list */
+ if (client_id_count) {
+ /* Check all Client ID's received in the command packet */
+ for (i = 0; i < client_id_count; i++) {
+ entry = silc_idlist_find_client_by_id(server->local_list,
+ client_id[i], NULL);
+ if (entry) {
+ clients = silc_realloc(clients, sizeof(*clients) *
+ (clients_count + 1));
+ clients[clients_count++] = entry;
+ }
+ }
+ } else {
+ clients = silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, server_name,
+ &clients_count);
+ }
+
+ /* Check global list as well */
+ if (!clients) {
+ if (client_id_count) {
+ /* Check all Client ID's received in the command packet */
+ for (i = 0; i < client_id_count; i++) {
+ entry = silc_idlist_find_client_by_id(server->global_list,
+ client_id[i], NULL);
+ if (entry) {
+ clients = silc_realloc(clients, sizeof(*clients) *
+ (clients_count + 1));
+ clients[clients_count++] = entry;
+ }
+ }
+ } else {
+ clients = silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, server_name,
+ &clients_count);
+ }
+ }
+
+ if (!clients) {
+ /* Such client(s) really does not exist in the SILC network. */
+ if (!client_id_count) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, nick, strlen(nick));
+ } else {
+ SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, idp->data, idp->len);
+ silc_buffer_free(idp);
+ }
+ goto out;
+ }
+
+ /* Router always finds the client entry if it exists in the SILC network.
+ However, it might be incomplete entry and does not include all the
+ mandatory fields that WHOIS command reply requires. Check for these and
+ make query from the server who owns the client if some fields are
+ missing. */
+ if (!silc_server_command_whois_check(cmd, clients, clients_count)) {
+ ret = -1;
+ goto out;
+ }
- silc_free(clients);
+ /* Send the command reply to the client */
+ silc_server_command_whois_send_reply(cmd, clients, clients_count);
- if (client_id)
+ out:
+ if (client_id_count) {
+ for (i = 0; i < client_id_count; i++)
+ silc_free(client_id[i]);
silc_free(client_id);
+ }
+ if (clients)
+ silc_free(clients);
+ if (nick)
+ silc_free(nick);
+ if (server_name)
+ silc_free(server_name);
+
+ return ret;
+}
+
+static int
+silc_server_command_whois_from_server(SilcServerCommandContext cmd)
+{
+ SilcServer server = cmd->server;
+ char *nick = NULL, *server_name = NULL;
+ int count = 0, clients_count = 0;
+ SilcClientEntry *clients = NULL, entry;
+ SilcClientID **client_id = NULL;
+ unsigned int client_id_count = 0;
+ int i, ret = 0;
+
+ /* Parse the whois request */
+ if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
+ &nick, &server_name, &count,
+ SILC_COMMAND_WHOIS))
+ return 0;
+
+ /* Process the command request. Let's search for the requested client and
+ send reply to the requesting server. */
+
+ if (client_id_count) {
+ /* Check all Client ID's received in the command packet */
+ for (i = 0; i < client_id_count; i++) {
+ entry = silc_idlist_find_client_by_id(server->local_list,
+ client_id[i], NULL);
+ if (entry) {
+ clients = silc_realloc(clients, sizeof(*clients) *
+ (clients_count + 1));
+ clients[clients_count++] = entry;
+ }
+ }
+ } else {
+ 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) {
+ if (client_id_count) {
+ /* Check all Client ID's received in the command packet */
+ for (i = 0; i < client_id_count; i++) {
+ entry = silc_idlist_find_client_by_id(server->global_list,
+ client_id[i], NULL);
+ if (entry) {
+ clients = silc_realloc(clients, sizeof(*clients) *
+ (clients_count + 1));
+ clients[clients_count++] = entry;
+ }
+ }
+ } else {
+ 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. */
+ if (!client_id_count) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, nick, strlen(nick));
+ } else {
+ SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, idp->data, idp->len);
+ silc_buffer_free(idp);
+ }
+ goto out;
+ }
+
+ /* Router always finds the client entry if it exists in the SILC network.
+ However, it might be incomplete entry and does not include all the
+ mandatory fields that WHOIS command reply requires. Check for these and
+ make query from the server who owns the client if some fields are
+ missing. */
+ if (!silc_server_command_whois_check(cmd, clients, clients_count)) {
+ ret = -1;
+ goto out;
+ }
+
+ /* Send the command reply to the client */
+ silc_server_command_whois_send_reply(cmd, clients, clients_count);
out:
- silc_server_command_free(cmd);
+ if (client_id_count) {
+ for (i = 0; i < client_id_count; i++)
+ silc_free(client_id[i]);
+ silc_free(client_id);
+ }
+ if (clients)
+ silc_free(clients);
+ if (nick)
+ silc_free(nick);
+ if (server_name)
+ silc_free(server_name);
+
+ return ret;
+}
+
+/* Server side of command WHOIS. Processes user's query and sends found
+ results as command replies back to the client. */
+
+SILC_SERVER_CMD_FUNC(whois)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ int ret;
+
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOIS, cmd, 1, 3328);
+
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ ret = silc_server_command_whois_from_client(cmd);
+ else
+ ret = silc_server_command_whois_from_server(cmd);
+
+ if (!ret)
+ silc_server_command_free(cmd);
}
SILC_SERVER_CMD_FUNC(whowas)
{
}
-SILC_SERVER_CMD_FUNC(identify)
+/******************************************************************************
+
+ IDENTIFY Functions
+
+******************************************************************************/
+
+/* Checks that all mandatory fields are present. If not then send WHOIS
+ request to the server who owns the client. We use WHOIS because we want
+ to get as much information as possible at once. */
+
+static char
+silc_server_command_identify_check(SilcServerCommandContext cmd,
+ SilcClientEntry *clients,
+ unsigned int clients_count)
{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
- char *tmp, *nick = NULL, *server_name = NULL;
- unsigned int argc, count = 0, len;
- int use_id = FALSE;
- SilcClientID *client_id = NULL;
+ int i;
SilcClientEntry entry;
+
+ for (i = 0; i < clients_count; i++) {
+ entry = clients[i];
+
+ if (!entry->nickname) {
+ SilcBuffer tmpbuf;
+ unsigned short old_ident;
+
+ if (!entry->router)
+ continue;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ silc_command_set_command(cmd->payload, SILC_COMMAND_WHOIS);
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ /* Send WHOIS request. We send WHOIS since we're doing the requesting
+ now anyway so make it a good one. */
+ silc_server_packet_send(server, entry->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply */
+ silc_server_command_pending(server, SILC_COMMAND_WHOIS,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_identify, (void *)cmd);
+ cmd->pending = TRUE;
+
+ /* Put old data back to the Command Payload we just changed */
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_command_set_command(cmd->payload, SILC_COMMAND_IDENTIFY);
+
+ silc_buffer_free(tmpbuf);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+silc_server_command_identify_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;
+ SilcCommandStatus status;
+ unsigned short ident = silc_command_get_ident(cmd->payload);
- SILC_LOG_DEBUG(("Start"));
+ status = SILC_STATUS_OK;
+ if (clients_count > 1)
+ status = SILC_STATUS_LIST_START;
- argc = silc_argument_get_arg_num(cmd->args);
- if (argc < 1) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
+ for (i = 0; i < clients_count; i++) {
+ entry = clients[i];
+
+ if (count && i - 1 == count)
+ break;
+
+ if (clients_count > 2)
+ status = SILC_STATUS_LIST_ITEM;
+
+ if (clients_count > 1 && i == clients_count - 1)
+ status = SILC_STATUS_LIST_END;
+
+ /* Send IDENTIFY reply */
+ 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];
+ SilcSocketConnection hsock;
+
+ 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);
+ }
+
+ if (!entry->username) {
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_OK, ident, 2,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh));
+ } else {
+ strncat(uh, entry->username, strlen(entry->username));
+ if (!strchr(entry->username, '@')) {
+ strncat(uh, "@", 1);
+ hsock = (SilcSocketConnection)entry->connection;
+ len = strlen(hsock->hostname);
+ strncat(uh, hsock->hostname, len);
+ }
+
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_OK, ident, 3,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh),
+ 4, uh, strlen(uh));
+ }
+
+ 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 (argc > 3) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
+}
+
+static int
+silc_server_command_identify_from_client(SilcServerCommandContext cmd)
+{
+ SilcServer server = cmd->server;
+ char *nick = NULL, *server_name = NULL;
+ int count = 0, clients_count = 0;
+ SilcClientEntry *clients = NULL, entry;
+ SilcClientID **client_id = NULL;
+ unsigned int client_id_count = 0;
+ int i, ret = 0;
+
+ /* Protocol dictates that we must always send the received IDENTIFY 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 IDENTIFY 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_IDENTIFY,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_identify, (void *)cmd);
+ cmd->pending = TRUE;
+
+ silc_command_set_ident(cmd->payload, old_ident);
+
+ silc_buffer_free(tmpbuf);
+ ret = -1;
goto out;
}
- /* If client ID is in the command it must be used instead of nickname */
- tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
- if (!tmp) {
+ /* We are ready to process the command request. Let's search for the
+ requested client and send reply to the requesting client. */
- /* Get the nickname@server string and parse it. */
- tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
- if (tmp) {
- if (strchr(tmp, '@')) {
- len = strcspn(tmp, "@");
- nick = silc_calloc(len + 1, sizeof(char));
- memcpy(nick, tmp, len);
- server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
- memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
- } else {
- nick = strdup(tmp);
+ /* Parse the IDENTIFY request */
+ if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
+ &nick, &server_name, &count,
+ SILC_COMMAND_IDENTIFY))
+ return 0;
+
+ /* Get all clients matching that ID or nickname from local list */
+ if (client_id_count) {
+ /* Check all Client ID's received in the command packet */
+ for (i = 0; i < client_id_count; i++) {
+ entry = silc_idlist_find_client_by_id(server->local_list,
+ client_id[i], NULL);
+ if (entry) {
+ clients = silc_realloc(clients, sizeof(*clients) *
+ (clients_count + 1));
+ clients[clients_count++] = entry;
}
- } else {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
}
} else {
- /* Command includes ID, use that */
- client_id = silc_id_payload_parse_id(tmp, len);
- use_id = TRUE;
+ clients = silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, server_name,
+ &clients_count);
}
-
- /* Get the max count of reply messages allowed */
- if (argc == 3) {
- tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
- if (!tmp) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
- goto out;
+
+ /* Check global list as well */
+ if (!clients) {
+ if (client_id_count) {
+ /* Check all Client ID's received in the command packet */
+ for (i = 0; i < client_id_count; i++) {
+ entry = silc_idlist_find_client_by_id(server->global_list,
+ client_id[i], NULL);
+ if (entry) {
+ clients = silc_realloc(clients, sizeof(*clients) *
+ (clients_count + 1));
+ clients[clients_count++] = entry;
+ }
+ }
+ } else {
+ clients = silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, server_name,
+ &clients_count);
+ }
+ }
+
+ if (!clients) {
+ /* Such a client really does not exist in the SILC network. */
+ if (!client_id_count) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, nick, strlen(nick));
+ } else {
+ SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, idp->data, idp->len);
+ silc_buffer_free(idp);
}
- count = atoi(tmp);
+ goto out;
}
- /* Find client */
- if (!use_id) {
- entry = silc_idlist_find_client_by_nickname(server->local_list,
- nick, NULL);
- if (!entry)
- entry = silc_idlist_find_client_by_hash(server->global_list,
- nick, server->md5hash);
- } else {
- entry = silc_idlist_find_client_by_id(server->local_list, client_id);
+ /* Check that all mandatory fields are present and request those data
+ from the server who owns the client if necessary. */
+ if (!cmd->pending &&
+ !silc_server_command_identify_check(cmd, clients, clients_count)) {
+ ret = -1;
+ goto out;
}
- /* If client was not found and if we are normal server and are connected
- to a router we will make global query from the router. */
- if (!entry && server->server_type == SILC_SERVER && !server->standalone &&
- !cmd->pending) {
- SilcBuffer buffer = cmd->packet->buffer;
-
- SILC_LOG_DEBUG(("Requesting identify from router"));
-
- /* Send IDENTIFY command to our router */
- silc_buffer_push(buffer, buffer->data - buffer->head);
- silc_server_packet_forward(server, (SilcSocketConnection)
- server->router->connection,
- buffer->data, buffer->len, TRUE);
- return;
+ /* Send the command reply to the client */
+ silc_server_command_identify_send_reply(cmd, clients, clients_count);
+
+ out:
+ if (client_id_count) {
+ for (i = 0; i < client_id_count; i++)
+ silc_free(client_id[i]);
+ silc_free(client_id);
}
+ if (clients)
+ silc_free(clients);
+ if (nick)
+ silc_free(nick);
+ if (server_name)
+ silc_free(server_name);
+
+ return ret;
+}
- /* If we are router we have checked our local list by nickname and our
- global list by hash so far. It is possible that the client is still not
- found and we'll check it from local list by hash. */
- if (!entry && server->server_type == SILC_ROUTER)
- entry = silc_idlist_find_client_by_hash(server->local_list,
- nick, server->md5hash);
+static int
+silc_server_command_identify_from_server(SilcServerCommandContext cmd)
+{
+ SilcServer server = cmd->server;
+ char *nick = NULL, *server_name = NULL;
+ int count = 0, clients_count = 0;
+ SilcClientEntry *clients = NULL, entry;
+ SilcClientID **client_id = NULL;
+ unsigned int client_id_count = 0;
+ int i, ret = 0;
+
+ /* Parse the IDENTIFY request */
+ if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
+ &nick, &server_name, &count,
+ SILC_COMMAND_IDENTIFY))
+ return 0;
+
+ /* Process the command request. Let's search for the requested client and
+ send reply to the requesting server. */
+
+ if (client_id_count) {
+ /* Check all Client ID's received in the command packet */
+ for (i = 0; i < client_id_count; i++) {
+ entry = silc_idlist_find_client_by_id(server->local_list,
+ client_id[i], NULL);
+ if (entry) {
+ clients = silc_realloc(clients, sizeof(*clients) *
+ (clients_count + 1));
+ clients[clients_count++] = entry;
+ }
+ }
+ } else {
+ 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) {
+ if (client_id_count) {
+ /* Check all Client ID's received in the command packet */
+ for (i = 0; i < client_id_count; i++) {
+ entry = silc_idlist_find_client_by_id(server->global_list,
+ client_id[i], NULL);
+ if (entry) {
+ clients = silc_realloc(clients, sizeof(*clients) *
+ (clients_count + 1));
+ clients[clients_count++] = entry;
+ }
+ }
+ } else {
+ 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 (!entry) {
- /* The client definitely does not exist */
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, tmp, strlen(tmp));
+ if (!clients) {
+ /* Such a client really does not exist in the SILC network. */
+ if (!client_id_count) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, nick, strlen(nick));
+ } else {
+ SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, idp->data, idp->len);
+ silc_buffer_free(idp);
+ }
goto out;
}
- /* Send IDENTIFY reply */
- idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
- tmp = silc_argument_get_first_arg(cmd->args, NULL);
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
- SILC_STATUS_OK, 0, 2,
- 2, idp->data, idp->len,
- 3, nick, strlen(nick));
- if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
- void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
- silc_server_packet_send_dest(server, cmd->sock,
- SILC_PACKET_COMMAND_REPLY, 0,
- id, cmd->packet->src_id_type,
- packet->data, packet->len, FALSE);
- silc_free(id);
- } else {
- silc_server_packet_send(server, cmd->sock,
- SILC_PACKET_COMMAND_REPLY, 0,
- packet->data, packet->len, FALSE);
+ /* Check that all mandatory fields are present and request those data
+ from the server who owns the client if necessary. */
+ if (!cmd->pending &&
+ !silc_server_command_identify_check(cmd, clients, clients_count)) {
+ ret = -1;
+ goto out;
}
- silc_buffer_free(packet);
- silc_buffer_free(idp);
- if (client_id)
- silc_free(client_id);
+ /* Send the command reply */
+ silc_server_command_identify_send_reply(cmd, clients, clients_count);
out:
+ if (client_id_count) {
+ for (i = 0; i < client_id_count; i++)
+ silc_free(client_id[i]);
+ silc_free(client_id);
+ }
+ if (clients)
+ silc_free(clients);
if (nick)
silc_free(nick);
if (server_name)
silc_free(server_name);
- silc_server_command_free(cmd);
+
+ return ret;
+}
+
+SILC_SERVER_CMD_FUNC(identify)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ int ret;
+
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
+
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ ret = silc_server_command_identify_from_client(cmd);
+ else
+ ret = silc_server_command_identify_from_server(cmd);
+
+ if (!ret)
+ silc_server_command_free(cmd);
}
/* Checks string for bad characters and returns TRUE if they are found. */
SilcClientID *new_id;
char *nick;
- SILC_LOG_DEBUG(("Start"));
-
- /* Check number of arguments */
- if (silc_argument_get_arg_num(cmd->args) < 1) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_NICK, cmd, 1, 1);
/* Check nickname */
nick = silc_argument_get_arg_type(cmd->args, 1, NULL);
/* 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. */
- if (!cmd->server->standalone)
+ if (!server->standalone)
silc_server_send_replace_id(server, server->router->connection,
server->server_type == SILC_SERVER ?
FALSE : TRUE, client->id,
unsigned char *tmp;
unsigned int argc, tmp_len;
- /* Check number of arguments */
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_TOPIC, cmd, 1, 2);
+
argc = silc_argument_get_arg_num(cmd->args);
- if (argc < 1) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- if (argc > 2) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
- goto out;
- }
/* Get Channel ID */
tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
goto out;
}
channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
/* Check whether the channel exists */
- channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+ 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);
idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
/* Send notify about topic change to all clients on the channel */
- silc_server_send_notify_to_channel(server, channel, TRUE,
+ silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
SILC_NOTIFY_TYPE_TOPIC_SET, 2,
idp->data, idp->len,
channel->topic, strlen(channel->topic));
SilcChannelID *channel_id;
SilcBuffer sidp;
unsigned char *tmp;
- unsigned int argc, len;
+ unsigned int len;
- /* Check number of arguments */
- argc = silc_argument_get_arg_num(cmd->args);
- if (argc < 1) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- if (argc > 2) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
- goto out;
- }
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 2);
/* Get destination ID */
tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
goto out;
}
dest_id = silc_id_payload_parse_id(tmp, len);
+ if (!dest_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NO_CLIENT_ID);
+ goto out;
+ }
/* Get Channel ID */
tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
goto out;
}
channel_id = silc_id_payload_parse_id(tmp, len);
+ if (!channel_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
/* Check whether the channel exists */
- channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+ 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);
if (chl->client == sender) {
if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
goto out;
}
break;
/* Find the connection data for the destination. If it is local we will
send it directly otherwise we will send it to router for routing. */
- dest = silc_idlist_find_client_by_id(server->local_list, dest_id);
+ dest = silc_idlist_find_client_by_id(server->local_list, dest_id, NULL);
if (dest)
dest_sock = (SilcSocketConnection)dest->connection;
else
- dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
+ dest_sock = silc_server_route_get(server, dest_id, SILC_ID_CLIENT);
/* Check whether the requested client is already on the channel. */
/* XXX if we are normal server we don't know about global clients on
- the channel thus we must request it (NAMES command), check from
+ the channel thus we must request it (USERS command), check from
local cache as well. */
if (silc_server_client_on_channel(dest, channel)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcBuffer packet, idp;
- unsigned int argc;
char info_string[256], *dest_server;
- argc = silc_argument_get_arg_num(cmd->args);
- if (argc < 1) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- if (argc > 1) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
- goto out;
- }
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 1);
/* Get server name */
dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcServerID *id;
- unsigned int argc, len;
+ unsigned int len;
unsigned char *tmp;
- argc = silc_argument_get_arg_num(cmd->args);
- if (argc < 1) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- if (argc > 2) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
- goto out;
- }
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 2);
/* Get Server ID */
tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
SILC_STATUS_ERR_NO_SERVER_ID);
goto out;
}
- id = silc_id_str2id(tmp, SILC_ID_SERVER);
+ id = silc_id_str2id(tmp, len, SILC_ID_SERVER);
if (!id)
goto out;
{
}
-typedef struct {
- char *channel_name;
- char *nickname;
- char *username;
- char *hostname;
- SilcChannelEntry channel;
- SilcServer server;
- SilcClientEntry client;
-} JoinInternalContext;
-
-SILC_TASK_CALLBACK(silc_server_command_join_notify)
-{
- JoinInternalContext *ctx = (JoinInternalContext *)context;
-
- if (ctx->channel->key && ctx->channel->key_len) {
- SilcBuffer clidp;
-
- clidp = silc_id_payload_encode(ctx->client->id, SILC_ID_CLIENT);
-
- silc_server_send_notify_to_channel(ctx->server, ctx->channel, FALSE,
- SILC_NOTIFY_TYPE_JOIN, 1,
- clidp->data, clidp->len);
-#if 0
- /* Send NEW_CHANNEL_USER packet to primary route */
- 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);
-#endif
-
- /* Send NAMES command reply to the joined channel so the user sees who
- is currently on the channel. */
- silc_server_command_send_names(ctx->server, ctx->client->connection,
- ctx->channel);
-
- silc_buffer_free(clidp);
- silc_free(ctx);
- } else {
- silc_task_register(ctx->server->timeout_queue, fd,
- silc_server_command_join_notify, context,
- 0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
- }
-}
-
-/* Assembles NAMES command and executes it. This is called when client
- joins to a channel and we wan't to send NAMES command reply to the
+/* 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_names(SilcServer server,
+void silc_server_command_send_users(SilcServer server,
SilcSocketConnection sock,
- SilcChannelEntry channel)
+ 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_NAMES, 0, 1,
+ 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_calloc(1, sizeof(*cmd));
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 = sock;
+ cmd->packet = silc_packet_context_dup(packet);
cmd->pending = FALSE;
- silc_server_command_names((void *)cmd);
- silc_free(buffer);
- silc_free(idp);
+ 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. */
+ silc_server_command_pending(server, SILC_COMMAND_USERS, 0,
+ silc_server_command_users, (void *)cmd);
+ cmd->pending = TRUE;
+ silc_buffer_free(buffer);
+ silc_buffer_free(idp);
+ return;
+ }
+
+ /* Process USERS command. */
+ silc_server_command_users((void *)cmd);
+
+ silc_buffer_free(buffer);
+ silc_buffer_free(idp);
+ silc_packet_context_free(packet);
}
/* Internal routine to join channel. The channel sent to this function
static void silc_server_command_join_channel(SilcServer server,
SilcServerCommandContext cmd,
SilcChannelEntry channel,
+ SilcClientID *client_id,
int created,
unsigned int umode)
{
SilcSocketConnection sock = cmd->sock;
unsigned char *tmp;
unsigned int tmp_len;
- unsigned char *passphrase = NULL, mode[4];
+ unsigned char *passphrase = NULL, mode[4], tmp2[4];
SilcClientEntry client;
SilcChannelClientEntry chl;
- SilcBuffer reply, chidp, clidp;
+ SilcBuffer reply, chidp, clidp, keyp;
+ unsigned short ident = silc_command_get_ident(cmd->payload);
+
+ SILC_LOG_DEBUG(("Start"));
if (!channel)
return;
/* Get passphrase */
- tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
if (tmp) {
passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
memcpy(passphrase, tmp, tmp_len);
* Client is allowed to join to the channel. Make it happen.
*/
- /* If the JOIN request was forwarded to us we will make a bit slower
- query to get the client pointer. Otherwise, we get the client pointer
- real easy. */
- if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
- void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
- client = silc_idlist_find_client_by_id(server->local_list, id);
+ /* Get the client entry */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+ client = (SilcClientEntry)sock->user_data;
+ } else {
+ client = silc_idlist_find_client_by_id(server->local_list, client_id,
+ NULL);
if (!client) {
- /* XXX */
- SILC_LOG_ERROR(("Forwarded join command did not find the client who "
- "wanted to join the channel"));
- goto out;
+ /* XXX actually this is useless since router finds always cell's
+ local clients from its local lists. */
+ client = silc_idlist_find_client_by_id(server->global_list, client_id,
+ NULL);
+ if (!client)
+ goto out;
}
- silc_free(id);
- } else {
- client = (SilcClientEntry)sock->user_data;
}
/* Check whether the client already is on the channel */
}
/* Generate new channel key as protocol dictates */
- if (!created)
+ if (!created || !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);
+
/* 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-
referencing. */
/* Encode command reply packet */
chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
SILC_PUT32_MSB(channel->mode, mode);
+ SILC_PUT32_MSB(created, tmp2);
+ tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ keyp = silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp,
+ SILC_ID_CHANNEL_LEN,
+ 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, 0, 3,
+ SILC_STATUS_OK, ident, 5,
2, channel->channel_name,
strlen(channel->channel_name),
3, chidp->data, chidp->len,
- 4, mode, 4);
+ 4, mode, 4,
+ 5, tmp2, 4,
+ 6, keyp->data, keyp->len);
} else {
reply =
silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
- SILC_STATUS_OK, 0, 4,
+ SILC_STATUS_OK, ident, 6,
2, channel->channel_name,
strlen(channel->channel_name),
3, chidp->data, chidp->len,
4, mode, 4,
- 5, channel->topic,
+ 5, tmp2, 4,
+ 6, keyp->data, keyp->len,
+ 8, channel->topic,
strlen(channel->topic));
}
-
- if (server->server_type == SILC_ROUTER &&
- cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
- /* We are router and server has forwarded this command to us. Send
- all replys to the server. */
- void *tmpid;
-
- /* Send command reply destined to the original client */
- tmpid = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
- silc_server_packet_send_dest(cmd->server, sock,
- SILC_PACKET_COMMAND_REPLY, 0,
- tmpid, cmd->packet->src_id_type,
- reply->data, reply->len, FALSE);
-
- /* Distribute new channel key to local cell and local clients. */
- silc_server_send_channel_key(server, sock, channel, TRUE);
-
- /* Distribute JOIN notify into the cell for everbody on the channel */
- silc_server_send_notify_to_channel(server, channel, FALSE,
- SILC_NOTIFY_TYPE_JOIN, 1,
- clidp->data, clidp->len);
-
- /* Broadcast NEW_CHANNEL_USER packet to primary route */
- silc_server_send_new_channel_user(server, server->router->connection,
- TRUE, channel->id, SILC_ID_CHANNEL_LEN,
- client->id, SILC_ID_CLIENT_LEN);
- silc_free(tmpid);
- } else {
- /* Client sent the command. Send all replies directly to the client. */
-
- /* Send command reply */
- silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
- reply->data, reply->len, FALSE);
+ /* Send command reply */
+ silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
+ reply->data, reply->len, FALSE);
- /* Send the channel key. Channel key is sent before any other packet
- to the channel. */
- silc_server_send_channel_key(server, sock, channel, server->standalone ?
- FALSE : TRUE);
-
+ if (!cmd->pending) {
/* Send JOIN notify to locally connected clients on the channel */
- silc_server_send_notify_to_channel(server, channel, FALSE,
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
SILC_NOTIFY_TYPE_JOIN, 1,
clidp->data, clidp->len);
/* Send NEW_CHANNEL_USER packet to our primary router */
if (!server->standalone)
silc_server_send_new_channel_user(server, server->router->connection,
- FALSE,
+ server->server_type == SILC_SERVER ?
+ FALSE : TRUE,
channel->id, SILC_ID_CHANNEL_LEN,
client->id, SILC_ID_CLIENT_LEN);
-
- /* Send NAMES command reply to the joined channel so the user sees who
- is currently on the channel. */
- silc_server_command_send_names(server, sock, channel);
}
+ /* 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);
out:
if (passphrase)
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
- int argc, tmp_len;
+ int tmp_len;
char *tmp, *channel_name = NULL, *cipher = NULL;
SilcChannelEntry channel;
unsigned int umode = 0;
int created = FALSE;
+ SilcClientID *client_id;
- SILC_LOG_DEBUG(("Start"));
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_JOIN, cmd, 1, 4);
- /* Check number of parameters */
- argc = silc_argument_get_arg_num(cmd->args);
- if (argc < 1) {
+ /* Get channel name */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!tmp) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- if (argc > 3) {
+ channel_name = tmp;
+
+ if (silc_server_command_bad_chars(channel_name) == TRUE) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
+ SILC_STATUS_ERR_BAD_CHANNEL);
+ silc_free(channel_name);
goto out;
}
- /* Get channel name */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ /* Get Client ID of the client who is joining to the channel */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
if (!tmp) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- channel_name = tmp;
-
- if (silc_server_command_bad_chars(channel_name) == TRUE) {
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_BAD_CHANNEL);
- silc_free(channel_name);
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
/* Get cipher name */
- cipher = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
/* See if the channel exists */
- channel = silc_idlist_find_channel_by_name(server->local_list, channel_name);
- if (!channel) {
- /* Channel not found */
-
- /* If we are standalone server we don't have a router, we just create
- the channel by ourselves. */
- if (server->standalone) {
- channel = silc_server_create_new_channel(server, server->id, cipher,
- channel_name);
- umode |= SILC_CHANNEL_UMODE_CHANOP;
- umode |= SILC_CHANNEL_UMODE_CHANFO;
- created = TRUE;
- } else {
+ channel = silc_idlist_find_channel_by_name(server->local_list,
+ channel_name, NULL);
- /* The channel does not exist on our server. If we are normal server
- we will send JOIN command to our router which will handle the joining
- procedure (either creates the channel if it doesn't exist or joins
- the client to it). */
- if (server->server_type == SILC_SERVER) {
- /* Forward the original JOIN command to the router */
- silc_buffer_push(cmd->packet->buffer,
- cmd->packet->buffer->data -
- cmd->packet->buffer->head);
- silc_server_packet_forward(server, (SilcSocketConnection)
- server->router->connection,
- cmd->packet->buffer->data,
- cmd->packet->buffer->len, TRUE);
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+ /* If this is coming from client the Client ID in the command packet must
+ be same as the client's ID. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+ SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
+ if (SILC_ID_CLIENT_COMPARE(entry->id, client_id)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
+ }
+
+ if (!channel) {
+ /* Channel not found */
+
+ /* If we are standalone server we don't have a router, we just create
+ the channel by ourselves. */
+ if (server->standalone) {
+ channel = silc_server_create_new_channel(server, server->id, cipher,
+ channel_name);
+ umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+ created = TRUE;
+
+ } else {
+
+ /* The channel does not exist on our server. If we are normal server
+ we will send JOIN command to our router which will handle the
+ joining procedure (either creates the channel if it doesn't exist
+ or joins the client to it). */
+ if (server->server_type == SILC_SERVER) {
+ 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 JOIN 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_JOIN,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_join, context);
+ cmd->pending = TRUE;
+ return;
+ }
+
+ /* We are router and the channel does not seem exist so we will check
+ our global list as well for the channel. */
+ channel = silc_idlist_find_channel_by_name(server->global_list,
+ channel_name, NULL);
+ if (!channel) {
+ /* Channel really does not exist, create it */
+ channel = silc_server_create_new_channel(server, server->id, cipher,
+ channel_name);
+ umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+ created = TRUE;
+ }
+ }
+ }
+ } else {
+ if (!channel) {
+ /* Channel not found */
+
+ /* If the command came from router and/or we are normal server then
+ something went wrong with the joining as the channel was not found.
+ We can't do anything else but ignore this. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER ||
+ server->server_type == SILC_SERVER)
+ goto out;
/* We are router and the channel does not seem exist so we will check
our global list as well for the channel. */
channel = silc_idlist_find_channel_by_name(server->global_list,
- channel_name);
+ channel_name, NULL);
if (!channel) {
/* Channel really does not exist, create it */
channel = silc_server_create_new_channel(server, server->id, cipher,
channel_name);
- umode |= SILC_CHANNEL_UMODE_CHANOP;
- umode |= SILC_CHANNEL_UMODE_CHANFO;
+ umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
created = TRUE;
}
}
}
+ /* If the channel does not have global users and is also empty it means the
+ channel was created globally (by our router) and the client will be the
+ channel founder and operator. */
+ if (!channel->global_users && silc_list_count(channel->user_list) == 0) {
+ umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+ created = TRUE; /* Created globally by our router */
+ }
+
/* Join to the channel */
- silc_server_command_join_channel(server, cmd, channel, created, umode);
+ silc_server_command_join_channel(server, cmd, channel, client_id,
+ created, umode);
+
+ silc_free(client_id);
out:
silc_server_command_free(cmd);
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
- unsigned int argc;
char *motd;
int motd_len;
- SILC_LOG_DEBUG(("Start"));
-
- argc = silc_argument_get_arg_num(cmd->args);
- if (argc < 1) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- if (argc > 2) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
- goto out;
- }
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 2);
/* XXX show currently only our motd */
if (is_op && !is_fo)
return FALSE;
} else {
- if (channel->mode & SILC_CHANNEL_MODE_PRIVATE) {
+ if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
if (is_op && !is_fo)
return FALSE;
}
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
- SilcSocketConnection sock = cmd->sock;
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
SilcChannelID *channel_id;
- SilcClientID *client_id;
SilcChannelEntry channel;
SilcChannelClientEntry chl;
SilcBuffer packet, cidp;
unsigned char *tmp, *tmp_id, *tmp_mask;
unsigned int argc, mode_mask, tmp_len, tmp_len2;
- int i;
SILC_LOG_DEBUG(("Start"));
goto out;
}
channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
+ if (!channel_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
/* Get the channel mode mask */
tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
SILC_GET32_MSB(mode_mask, tmp_mask);
/* Get channel entry */
- channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+ 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);
/* Send CMODE_CHANGE notify */
cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
- silc_server_send_notify_to_channel(server, channel, TRUE,
+ silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
cidp->data, cidp->len,
tmp_mask, tmp_len);
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
- SilcSocketConnection sock = cmd->sock;
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
SilcChannelID *channel_id;
SilcClientID *client_id;
SilcClientEntry target_client;
SilcChannelClientEntry chl;
SilcBuffer packet, idp;
- unsigned char *tmp, *tmp_id, *tmp_mask;
- unsigned int argc, target_mask, sender_mask, tmp_len;
- int i, notify = FALSE;
-
- SILC_LOG_DEBUG(("Start"));
+ unsigned char *tmp_id, *tmp_mask;
+ unsigned int target_mask, sender_mask, tmp_len;
+ int notify = FALSE;
- argc = silc_argument_get_arg_num(cmd->args);
- if (argc < 3) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- if (argc > 3) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
- goto out;
- }
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 3);
/* Get Channel ID */
tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
goto out;
}
channel_id = silc_id_payload_parse_id(tmp_id, tmp_len);
+ if (!channel_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
/* Get channel entry */
- channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+ 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;
}
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);
+ goto out;
+ }
/* Get target client's entry */
- target_client = silc_idlist_find_client_by_id(server->local_list, client_id);
+ target_client = silc_idlist_find_client_by_id(server->local_list,
+ client_id, NULL);
if (!target_client) {
/* XXX If target client is not one of mine send to primary route */
}
/* Send notify to channel, notify only if mode was actually changed. */
if (notify) {
idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
- silc_server_send_notify_to_channel(server, channel, TRUE,
+ silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
idp->data, idp->len,
tmp_mask, 4, tmp_id, tmp_len);
SILC_SERVER_CMD_FUNC(kick)
{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- SilcSocketConnection sock = cmd->sock;
- SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-
}
SILC_SERVER_CMD_FUNC(restart)
SilcChannelID *id;
SilcChannelEntry channel;
SilcBuffer packet;
- unsigned int i, argc, len;
+ unsigned int i, len;
unsigned char *tmp;
- SILC_LOG_DEBUG(("Start"));
-
- argc = silc_argument_get_arg_num(cmd->args);
- if (argc < 1) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- if (argc > 2) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
- goto out;
- }
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 2);
/* Get Channel ID */
tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
goto out;
}
id = silc_id_payload_parse_id(tmp, len);
+ if (!id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
/* Get channel entry */
- channel = silc_idlist_find_channel_by_id(server->local_list, id);
+ 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);
silc_server_packet_send(server,
cmd->server->router->connection,
SILC_PACKET_CHANNEL_KEY, 0, packet->data,
- packet->len, TRUE);
+ packet->len, FALSE);
} else {
}
silc_server_command_free(cmd);
}
-/* Server side of command NAMES. Resolves clients and their names currently
- joined on the requested channel. The name list is sent back to the
- client. */
+/* Server side of command USERS. Resolves clients and their USERS currently
+ joined on the requested channel. The list of Client ID's and their modes
+ on the channel is sent back. */
-SILC_SERVER_CMD_FUNC(names)
+SILC_SERVER_CMD_FUNC(users)
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcChannelClientEntry chl;
SilcChannelID *id;
SilcBuffer packet;
- unsigned int i, len, len2, tmp_len, argc;
- unsigned char *tmp;
- char *name_list = NULL, *n;
+ 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);
- SILC_LOG_DEBUG(("Start"));
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 1);
- argc = silc_argument_get_arg_num(cmd->args);
- if (argc < 1) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- if (argc > 2) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
+ /* Get Channel ID */
+ channel_id = silc_argument_get_arg_type(cmd->args, 1, &channel_id_len);
+ if (!channel_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
goto out;
}
-
- /* 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_LEAVE,
+ id = silc_id_payload_parse_id(channel_id, channel_id_len);
+ if (!id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
SILC_STATUS_ERR_NO_CHANNEL_ID);
goto out;
}
- id = silc_id_payload_parse_id(tmp, tmp_len);
- /* Check whether the channel exists. If we are normal server and the
- channel does not exist we will send this same command to our router
- which will know if the channel exists. */
- channel = silc_idlist_find_channel_by_id(server->local_list, id);
+ /* If we are server and we don't know about this channel we will send
+ the command to our router. If we know about the channel then we also
+ have the list of users already. */
+ channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
if (!channel) {
- if (server->server_type == SILC_SERVER && !server->standalone) {
- /* XXX Send names command */
-
+ if (server->server_type == SILC_SERVER && !server->standalone &&
+ !cmd->pending) {
+ SilcBuffer tmpbuf;
+
+ silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ /* Send USERS command */
+ silc_server_packet_send(server, server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply */
+ silc_server_command_pending(server, SILC_COMMAND_USERS,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_users, (void *)cmd);
cmd->pending = TRUE;
- silc_server_command_pending(server, SILC_COMMAND_NAMES, 0,
- silc_server_command_names, context);
+ silc_command_set_ident(cmd->payload, ident);
+
+ silc_buffer_free(tmpbuf);
+ silc_free(id);
return;
}
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL);
- goto out;
- }
-
- /* Assemble the name list now */
- name_list = NULL;
- len = 0;
- silc_list_start(channel->user_list);
- i = 0;
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
- n = chl->client->nickname;
- if (n) {
- len2 = strlen(n);
- len += len2;
- name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
- memcpy(name_list + (len - len2), n, len2);
- name_list[len] = 0;
-
- if (i == silc_list_count(channel->user_list) - 1)
- break;
- memcpy(name_list + len, ",", 1);
- len++;
- i++;
+ /* We are router and we will check the global list as well. */
+ channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
+ if (!channel) {
+ /* Channel really does not exist */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
}
}
- if (!name_list)
- name_list = "";
- /* Assemble the Client ID list now */
+ /* 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) {
- SilcBuffer idp;
-
+ /* Client ID */
idp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
- silc_buffer_format(client_id_list,
- SILC_STR_UI_XNSTRING(idp->data, idp->len),
- SILC_STR_END);
+ silc_buffer_put(client_id_list, idp->data, idp->len);
silc_buffer_pull(client_id_list, idp->len);
silc_buffer_free(idp);
- }
- silc_buffer_push(client_id_list,
- client_id_list->data - client_id_list->head);
- /* Assemble mode 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'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);
+ /* List count */
+ SILC_PUT32_MSB(list_count, lc);
+
/* Send reply */
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NAMES,
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
SILC_STATUS_OK, 0, 4,
- 2, tmp, tmp_len,
- 3, name_list,
- strlen(name_list),
+ 2, channel_id, channel_id_len,
+ 3, lc, 4,
4, client_id_list->data,
client_id_list->len,
5, client_mode_list->data,
packet->data, packet->len, FALSE);
silc_buffer_free(packet);
- silc_free(name_list);
silc_buffer_free(client_id_list);
silc_buffer_free(client_mode_list);
silc_free(id);