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
static void silc_server_command_free(SilcServerCommandContext cmd);
void silc_server_command_send_users(SilcServer server,
SilcSocketConnection sock,
- SilcChannelEntry channel);
+ SilcChannelEntry channel,
+ int pending);
/* Server command list. */
SilcServerCommand silc_command_list[] =
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);
*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 (tmp) {
*client_id = silc_realloc(*client_id, sizeof(**client_id) *
(*client_id_count + 1));
- (*client_id)[k++] = silc_id_payload_parse_id(tmp, len);
+ (*client_id)[k] = silc_id_payload_parse_id(tmp, len);
+ if ((*client_id)[k] == NULL) {
+ for (i = 0; i < k; i++)
+ silc_free((*client_id)[i]);
+ silc_free(*client_id);
+ return FALSE;
+ }
(*client_id_count)++;
+ k++;
}
}
}
if (!entry->nickname || !entry->username || !entry->userinfo) {
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));
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
int ret;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOIS, cmd, 1, 3);
+ 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);
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);
{
SilcServer server = cmd->server;
char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count;
+ int count = 0, clients_count = 0;
SilcClientEntry *clients = NULL, entry;
SilcClientID **client_id = NULL;
unsigned int client_id_count = 0;
{
SilcServer server = cmd->server;
char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count;
+ int count = 0, clients_count = 0;
SilcClientEntry *clients = NULL, entry;
SilcClientID **client_id = NULL;
unsigned int client_id_count = 0;
if (!clients) {
/* Such a client really does not exist in the SILC network. */
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, nick, strlen(nick));
+ 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;
}
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
int ret;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_IDENTIFY, cmd, 1, 3);
+ 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);
/* 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,
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,
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));
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,
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 USERS command reply to the joined channel so the user sees who
- is currently on the channel. */
- silc_server_command_send_users(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 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)
+ 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);
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_users((void *)cmd);
-
- silc_free(buffer);
- silc_free(idp);
- silc_packet_context_free(packet);
-}
-
-/* Internal routine that is called after router has replied to server's
- JOIN command it forwarded to the router. The route has joined and possibly
- creaetd the channel. This function adds the client to the channel's user
- list. */
-
-SILC_SERVER_CMD_FUNC(add_to_channel)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- SilcClientEntry client;
- SilcChannelEntry channel;
- SilcChannelClientEntry chl;
- char *channel_name;
-
- /* Get channel name */
- channel_name = silc_argument_get_arg_type(cmd->args, 1, NULL);
-
- /* Get client entry */
- client = (SilcClientEntry)cmd->sock->user_data;
-
- /* Get channel entry */
- channel = silc_idlist_find_channel_by_name(server->local_list,
- channel_name, NULL);
- if (channel) {
- /* 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. */
- chl = silc_calloc(1, sizeof(*chl));
- //chl->mode = SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO;
- chl->client = client;
- chl->channel = channel;
- silc_list_add(channel->user_list, chl);
- silc_list_add(client->channels, chl);
+ 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;
}
- silc_server_command_free(cmd);
+ /* 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
/* 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, channel,
+ silc_server_send_channel_key(server, NULL, channel,
server->server_type == SILC_ROUTER ?
FALSE : server->standalone);
silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
reply->data, reply->len, FALSE);
- if (!cmd->pending)
+ 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 (!cmd->pending && !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);
+ /* Send NEW_CHANNEL_USER 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);
+ }
/* 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);
-
- /*
-
- FAQ:
-
- * Kuinka USERS komento händlätään serverissä kun router lähettää sen
- serverille joka on lähettäny sille clientin puolesta JOIN komennon?
-
- R: Serverin pitää ymmärtää USERS comman replyjä.
-
- */
+ silc_server_command_send_users(server, sock, channel, cmd->pending);
silc_buffer_free(reply);
silc_buffer_free(clidp);
goto out;
}
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_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
/* Get cipher name */
cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
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);
/* 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);
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,
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,
/* 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);
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, NULL);
SilcChannelClientEntry chl;
SilcChannelID *id;
SilcBuffer packet;
- unsigned char *tmp;
- unsigned int tmp_len;
+ 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_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 2);
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 1);
/* Get Channel ID */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- if (!tmp) {
+ 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;
+ }
+ 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);
/* 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
/* 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_USERS,
SILC_STATUS_OK, 0, 4,
- 2, tmp, tmp_len,
- 3, client_id_list->data,
+ 2, channel_id, channel_id_len,
+ 3, lc, 4,
+ 4, client_id_list->data,
client_id_list->len,
- 4, client_mode_list->data,
+ 5, client_mode_list->data,
client_mode_list->len);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);