uint32 arg_type,
unsigned char *arg,
uint32 arg_len);
+static bool
+silc_server_command_pending_error_check(SilcServerCommandContext cmd,
+ SilcServerCommandReplyContext cmdr,
+ SilcCommand command);
SILC_TASK_CALLBACK(silc_server_command_process_timeout);
/* Server command list. */
{ NULL, 0 },
};
-#define SILC_SERVER_COMMAND_CHECK_ARGC(command, context, min, max) \
+/* Performs several checks to the command. It first checks whether this
+ command was called as pending command callback. If it was then it checks
+ whether error occurred in the command reply where the pending command
+ callback was called.
+
+ It also checks that the requested command includes correct amount
+ of arguments. */
+#define SILC_SERVER_COMMAND_CHECK(command, context, min, max) \
do { \
- uint32 _argc = silc_argument_get_arg_num(cmd->args); \
+ uint32 _argc; \
\
SILC_LOG_DEBUG(("Start")); \
\
+ if (silc_server_command_pending_error_check(cmd, context2, command)) { \
+ silc_server_command_free(cmd); \
+ return; \
+ } \
+ \
+ _argc = silc_argument_get_arg_num(cmd->args); \
if (_argc < min) { \
silc_server_command_send_status_reply(cmd, command, \
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
SilcCommand command)
{
SilcIDListData idata = (SilcIDListData)sock->user_data;
- if (idata->registered)
+
+ if (!idata)
+ return FALSE;
+
+ if (idata->status & SILC_IDLIST_STATUS_REGISTERED)
return TRUE;
silc_server_command_send_status_reply(cmd, command,
client->last_command = time(NULL);
if (!(timeout->cmd->flags & SILC_CF_REG))
- timeout->cmd->cb(timeout->ctx);
+ timeout->cmd->cb(timeout->ctx, NULL);
else if (silc_server_is_registered(timeout->ctx->server,
timeout->ctx->sock,
timeout->ctx,
timeout->cmd->cmd))
- timeout->cmd->cb(timeout->ctx);
+ timeout->cmd->cb(timeout->ctx, NULL);
silc_free(timeout);
}
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_schedule_task_add(server->schedule, 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_schedule_task_add(server->schedule, sock->sock,
silc_server_command_process_timeout,
(void *)timeout,
0, 1,
/* Execute for server */
if (!(cmd->flags & SILC_CF_REG))
- cmd->cb(ctx);
+ cmd->cb(ctx, NULL);
else if (silc_server_is_registered(server, sock, ctx, cmd->cmd))
- cmd->cb(ctx);
+ cmd->cb(ctx, NULL);
}
/* Allocate Command Context */
/* Add new pending command to be executed when reply to a command has been
received. The `reply_cmd' is the command that will call the `callback'
- with `context' when reply has been received. If `ident' is non-zero
+ with `context' when reply has been received. It can be SILC_COMMAND_NONE
+ to match any command with the `ident'. If `ident' is non-zero
the `callback' will be executed when received reply with command
identifier `ident'. */
/* Checks for pending commands and marks callbacks to be called from
the command reply function. Returns TRUE if there were pending command. */
-int silc_server_command_pending_check(SilcServer server,
- SilcServerCommandReplyContext ctx,
- SilcCommand command,
- uint16 ident)
+SilcServerCommandPendingCallbacks
+silc_server_command_pending_check(SilcServer server,
+ SilcServerCommandReplyContext ctx,
+ SilcCommand command,
+ uint16 ident,
+ uint32 *callbacks_count)
{
SilcServerCommandPending *r;
+ SilcServerCommandPendingCallbacks callbacks = NULL;
+ int i = 0;
silc_dlist_start(server->pending_commands);
while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
- if (r->reply_cmd == command && r->ident == ident) {
- ctx->context = r->context;
- ctx->callback = r->callback;
- ctx->destructor = r->destructor;
+ if ((r->reply_cmd == command || r->reply_cmd == SILC_COMMAND_NONE)
+ && r->ident == ident) {
+ callbacks = silc_realloc(callbacks, sizeof(*callbacks) * (i + 1));
+ callbacks[i].context = r->context;
+ callbacks[i].callback = r->callback;
+ callbacks[i].destructor = r->destructor;
ctx->ident = ident;
- return TRUE;
+ i++;
}
}
- return FALSE;
+ *callbacks_count = i;
+ return callbacks;
}
/* Destructor function for pending callbacks. This is called when using
silc_buffer_free(buffer);
}
+/* This function can be called to check whether in the command reply
+ an error occurred. This function has no effect if this is called
+ when the command function was not called as pending command callback.
+ This returns TRUE if error had occurred. */
+
+static bool
+silc_server_command_pending_error_check(SilcServerCommandContext cmd,
+ SilcServerCommandReplyContext cmdr,
+ SilcCommand command)
+{
+ SilcCommandStatus status;
+
+ if (!cmd->pending || !cmdr)
+ return FALSE;
+
+ SILC_GET16_MSB(status, silc_argument_get_arg_type(cmdr->args, 1, NULL));
+ if (status != SILC_STATUS_OK &&
+ status != SILC_STATUS_LIST_START &&
+ status != SILC_STATUS_LIST_ITEM &&
+ status != SILC_STATUS_LIST_END) {
+ /* Send the error message */
+ silc_server_command_send_status_reply(cmd, command, status);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/******************************************************************************
WHOIS Functions
/* 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, "@");
- *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);
- }
+ silc_parse_userfqdn(tmp, nickname, server_name);
} else {
silc_server_command_send_status_reply(cmd, command,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
}
}
}
-
- /* Command includes ID, use that */
}
/* Get the max count of reply messages allowed */
return TRUE;
}
-static char
+/* Resolve context used by both WHOIS and IDENTIFY commands */
+typedef struct {
+ SilcServerEntry router;
+ uint16 ident;
+ unsigned char **res_argv;
+ uint32 *res_argv_lens;
+ uint32 *res_argv_types;
+ uint32 res_argc;
+} *SilcServerResolveContext;
+
+static bool
silc_server_command_whois_check(SilcServerCommandContext cmd,
SilcClientEntry *clients,
uint32 clients_count)
{
SilcServer server = cmd->server;
- int i;
SilcClientEntry entry;
+ SilcServerResolveContext resolve = NULL, r = NULL;
+ uint32 resolve_count = 0;
+ int i, k;
+ bool no_res = TRUE;
for (i = 0; i < clients_count; i++) {
entry = clients[i];
- if (!entry || entry->data.registered == FALSE)
+ if (!entry || (entry->nickname && entry->username && entry->userinfo) ||
+ !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
+ !entry->router)
continue;
- if (!entry->nickname || !entry->username || !entry->userinfo) {
- SilcBuffer tmpbuf;
- uint16 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));
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+ /* We need to resolve this entry since it is not complete */
- /* 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),
+ if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
+ /* The entry is being resolved (and we are not the resolver) so attach
+ to the command reply and we're done with this one. */
+ silc_server_command_pending(server, SILC_COMMAND_NONE,
+ entry->resolve_cmd_ident,
silc_server_command_destructor,
- silc_server_command_whois,
+ silc_server_command_whois,
silc_server_command_dup(cmd));
- cmd->pending = TRUE;
-
- silc_command_set_ident(cmd->payload, old_ident);
+ no_res = FALSE;
+ } else {
+ if (entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
+ /* We've resolved this and it still is not ready. We'll return
+ and are that this will be handled again after it is resolved. */
+ for (i = 0; i < resolve_count; i++) {
+ for (k = 0; k < r->res_argc; k++)
+ silc_free(r->res_argv[k]);
+ silc_free(r->res_argv);
+ silc_free(r->res_argv_lens);
+ silc_free(r->res_argv_types);
+ }
+ silc_free(resolve);
+ return FALSE;
+ } else {
+ /* We'll resolve this client */
+ SilcBuffer idp;
+
+ r = NULL;
+ for (k = 0; k < resolve_count; k++) {
+ if (resolve[k].router == entry->router) {
+ r = &resolve[k];
+ break;
+ }
+ }
- silc_buffer_free(tmpbuf);
- return FALSE;
+ if (!r) {
+ resolve = silc_realloc(resolve, sizeof(*resolve) *
+ (resolve_count + 1));
+ r = &resolve[resolve_count];
+ memset(r, 0, sizeof(*r));
+ r->router = entry->router;
+ r->ident = ++server->cmd_ident;
+ resolve_count++;
+ }
+
+ r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) *
+ (r->res_argc + 1));
+ r->res_argv_lens = silc_realloc(r->res_argv_lens,
+ sizeof(*r->res_argv_lens) *
+ (r->res_argc + 1));
+ r->res_argv_types = silc_realloc(r->res_argv_types,
+ sizeof(*r->res_argv_types) *
+ (r->res_argc + 1));
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+ r->res_argv[r->res_argc] = silc_calloc(idp->len,
+ sizeof(**r->res_argv));
+ memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
+ r->res_argv_lens[r->res_argc] = idp->len;
+ r->res_argv_types[r->res_argc] = r->res_argc + 3;
+ r->res_argc++;
+ silc_buffer_free(idp);
+
+ entry->resolve_cmd_ident = r->ident;
+ entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
+ entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
+ }
}
}
- return TRUE;
+ /* Do the resolving */
+ for (i = 0; i < resolve_count; i++) {
+ SilcBuffer res_cmd;
+
+ r = &resolve[i];
+
+ /* Send WHOIS request. We send WHOIS since we're doing the requesting
+ now anyway so make it a good one. */
+ res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
+ r->res_argc, r->res_argv,
+ r->res_argv_lens,
+ r->res_argv_types,
+ r->ident);
+ silc_server_packet_send(server, r->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ res_cmd->data, res_cmd->len, FALSE);
+
+ /* Reprocess this packet after received reply */
+ silc_server_command_pending(server, SILC_COMMAND_WHOIS,
+ r->ident,
+ silc_server_command_destructor,
+ silc_server_command_whois,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+
+ silc_buffer_free(res_cmd);
+ for (k = 0; k < r->res_argc; k++)
+ silc_free(r->res_argv[k]);
+ silc_free(r->res_argv);
+ silc_free(r->res_argv_lens);
+ silc_free(r->res_argv_types);
+ no_res = FALSE;
+ }
+ silc_free(resolve);
+
+ return no_res;
}
static void
len = 0;
for (i = 0; i < clients_count; i++)
- if (clients[i]->data.registered)
+ if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
len++;
+ if (len == 0 && clients_count) {
+ entry = clients[0];
+ if (entry->nickname) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, entry->nickname,
+ strlen(entry->nickname));
+ } else {
+ SilcBuffer idp = silc_id_payload_encode(entry->id, 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);
+ }
+
+ return;
+ }
+
status = SILC_STATUS_OK;
if (len > 1)
status = SILC_STATUS_LIST_START;
for (i = 0, k = 0; i < clients_count; i++) {
entry = clients[i];
- if (entry->data.registered == FALSE) {
+ if (!(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
if (clients_count == 1) {
if (entry->nickname) {
silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
}
static int
-silc_server_command_whois_from_client(SilcServerCommandContext cmd)
+silc_server_command_whois_process(SilcServerCommandContext cmd)
{
SilcServer server = cmd->server;
char *nick = NULL, *server_name = NULL;
SilcClientID **client_id = NULL;
uint32 client_id_count = 0, clients_count = 0;
int i, ret = 0;
+ bool check_global = FALSE;
/* 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 &&
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
!server->standalone) {
SilcBuffer tmpbuf;
uint16 old_ident;
/* 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 {
- if (!silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients, &clients_count))
- silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients, &clients_count);
- }
-
- /* Check global list as well */
- 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 {
- if (!silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients, &clients_count))
- silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients, &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;
- }
-
- /* Send the command reply to the client */
- silc_server_command_whois_send_reply(cmd, clients, clients_count,
- 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;
-}
-
-static int
-silc_server_command_whois_from_server(SilcServerCommandContext cmd)
-{
- SilcServer server = cmd->server;
- char *nick = NULL, *server_name = NULL;
- int count = 0;
- SilcClientEntry *clients = NULL, entry;
- SilcClientID **client_id = NULL;
- uint32 client_id_count = 0, clients_count = 0;
- int i, ret = 0;
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ check_global = TRUE;
+ else if (server->server_type == SILC_ROUTER)
+ check_global = TRUE;
/* Parse the whois request */
if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count,
SILC_COMMAND_WHOIS))
return 0;
- /* Process the command request. Let's search for the requested client and
- send reply to the requesting server. */
-
+ /* 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);
+ client_id[i], TRUE, NULL);
+ if (!entry && check_global)
+ entry = silc_idlist_find_client_by_id(server->global_list,
+ client_id[i], TRUE, NULL);
if (entry) {
clients = silc_realloc(clients, sizeof(*clients) *
(clients_count + 1));
silc_idlist_get_clients_by_nickname(server->local_list,
nick, server_name,
&clients, &clients_count);
- }
-
- /* If we are router we will check our global list as well. */
- if (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 {
+ if (check_global) {
if (!silc_idlist_get_clients_by_hash(server->global_list,
nick, server->md5hash,
&clients, &clients_count))
&clients, &clients_count);
}
}
-
+
if (!clients) {
- /* Such a client really does not exist in the SILC network. */
+ /* 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,
goto out;
}
- /* Send the command reply to the client */
+ /* Send the command reply */
silc_server_command_whois_send_reply(cmd, clients, clients_count,
count);
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
int ret = 0;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOIS, cmd, 1, 3328);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 3328);
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
- ret = silc_server_command_whois_from_client(cmd);
- else if ((cmd->sock->type == SILC_SOCKET_TYPE_SERVER) ||
- (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER))
- ret = silc_server_command_whois_from_server(cmd);
+ ret = silc_server_command_whois_process(cmd);
if (!ret)
silc_server_command_free(cmd);
}
/* 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);
- }
+ silc_parse_userfqdn(tmp, nickname, server_name);
+
/* Get the max count of reply messages allowed */
tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
if (tmp)
/* 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)
+ if (entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
continue;
if (entry->id == NULL)
continue;
}
static int
-silc_server_command_whowas_from_client(SilcServerCommandContext cmd)
+silc_server_command_whowas_process(SilcServerCommandContext cmd)
{
SilcServer server = cmd->server;
char *nick = NULL, *server_name = NULL;
SilcClientEntry *clients = NULL;
uint32 clients_count = 0;
int ret = 0;
+ bool check_global = FALSE;
/* 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) {
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
SilcBuffer tmpbuf;
uint16 old_ident;
/* We are ready to process the command request. Let's search for the
requested client and send reply to the requesting client. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ check_global = TRUE;
+ else if (server->server_type == SILC_ROUTER)
+ check_global = TRUE;
+
/* Parse the whowas request */
if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
return 0;
&clients, &clients_count);
/* Check global list as well */
- if (!silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients, &clients_count))
- silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients, &clients_count);
+ if (check_global) {
+ if (!silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, server_name,
+ &clients, &clients_count))
+ silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ &clients, &clients_count);
+ }
- if (!silc_server_command_whowas_check(cmd, clients, 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;
+ }
+
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ !silc_server_command_whowas_check(cmd, clients, clients_count)) {
ret = -1;
goto out;
}
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);
+ silc_free(clients);
+ silc_free(nick);
+ silc_free(server_name);
return ret;
}
-static int
-silc_server_command_whowas_from_server(SilcServerCommandContext cmd)
+/* Server side of command WHOWAS. */
+
+SILC_SERVER_CMD_FUNC(whowas)
{
- SilcServer server = cmd->server;
- char *nick = NULL, *server_name = NULL;
- int count = 0;
- SilcClientEntry *clients = NULL;
- uint32 clients_count = 0;
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
int ret = 0;
- /* Parse the whowas request */
- if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
- return 0;
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOWAS, cmd, 1, 2);
- /* Process the command request. Let's search for the requested client and
- send reply to the requesting server. */
+ ret = silc_server_command_whowas_process(cmd);
- if (!silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients, &clients_count))
- silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients, &clients_count);
-
- /* If we are router we will check our global list as well. */
- if (server->server_type == SILC_ROUTER) {
- if (!silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients, &clients_count))
- silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients, &clients_count);
- }
+ if (!ret)
+ silc_server_command_free(cmd);
+}
- 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);
+ IDENTIFY Functions
- out:
- if (clients)
- silc_free(clients);
- if (nick)
- silc_free(nick);
- if (server_name)
- silc_free(server_name);
+******************************************************************************/
- return ret;
-}
+static bool
+silc_server_command_identify_parse(SilcServerCommandContext cmd,
+ SilcClientEntry **clients,
+ uint32 *clients_count,
+ SilcServerEntry **servers,
+ uint32 *servers_count,
+ SilcChannelEntry **channels,
+ uint32 *channels_count,
+ uint32 *count)
+{
+ SilcServer server = cmd->server;
+ unsigned char *tmp;
+ uint32 len;
+ uint32 argc = silc_argument_get_arg_num(cmd->args);
+ SilcIDPayload idp;
+ bool check_global = FALSE;
+ void *entry;
+ int i;
+ bool error = FALSE;
-/* Server side of command WHOWAS. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ check_global = TRUE;
+ else if (server->server_type == SILC_ROUTER)
+ check_global = TRUE;
-SILC_SERVER_CMD_FUNC(whowas)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- int ret = 0;
+ /* If ID Payload is in the command it must be used instead of names */
+ tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
+ if (!tmp) {
+ /* No ID, get the names. */
+
+ /* Try to get nickname@server. */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ if (tmp) {
+ char *nick = NULL;
+ char *nick_server = NULL;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOWAS, cmd, 1, 2);
+ silc_parse_userfqdn(tmp, &nick, &nick_server);
- 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 (!silc_idlist_get_clients_by_hash(server->local_list,
+ nick, server->md5hash,
+ clients, clients_count))
+ silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, nick_server,
+ clients, clients_count);
+ if (check_global) {
+ if (!silc_idlist_get_clients_by_hash(server->global_list,
+ nick, server->md5hash,
+ clients, clients_count))
+ silc_idlist_get_clients_by_nickname(server->global_list,
+ nick, nick_server,
+ clients, clients_count);
+ }
- if (!ret)
- silc_server_command_free(cmd);
-}
+ silc_free(nick);
+ silc_free(nick_server);
-/******************************************************************************
+ if (!(*clients)) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, tmp, strlen(tmp));
+ return FALSE;
+ }
+ }
- IDENTIFY Functions
+ /* Try to get server name */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (tmp) {
+ entry = silc_idlist_find_server_by_name(server->local_list,
+ tmp, TRUE, NULL);
+ if (!entry && check_global)
+ entry = silc_idlist_find_server_by_name(server->local_list,
+ tmp, TRUE, NULL);
+ if (entry) {
+ *servers = silc_realloc(*servers, sizeof(**servers) *
+ (*servers_count + 1));
+ (*servers)[(*servers_count)++] = entry;
+ }
-******************************************************************************/
+ if (!(*servers)) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_SERVER,
+ 3, tmp, strlen(tmp));
+ return FALSE;
+ }
+ }
-/* 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. */
+ /* Try to get channel name */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ if (tmp) {
+ entry = silc_idlist_find_channel_by_name(server->local_list,
+ tmp, NULL);
+ if (!entry && check_global)
+ entry = silc_idlist_find_channel_by_name(server->local_list,
+ tmp, NULL);
+ if (entry) {
+ *channels = silc_realloc(*channels, sizeof(**channels) *
+ (*channels_count + 1));
+ (*channels)[(*channels_count)++] = entry;
+ }
-static char
-silc_server_command_identify_check(SilcServerCommandContext cmd,
- SilcClientEntry *clients,
- uint32 clients_count)
+ if (!(*channels)) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL,
+ 3, tmp, strlen(tmp));
+ return FALSE;
+ }
+ }
+
+ if (!(*clients) && !(*servers) && !(*channels)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return FALSE;
+ }
+ } else {
+ /* Command includes ID, we must use that. Also check whether the command
+ has more than one ID set - take them all. */
+
+ /* Take all ID's from the command packet */
+ for (i = 0; i < argc; i++) {
+ void *id;
+
+ tmp = silc_argument_get_arg_type(cmd->args, i + 5, &len);
+ if (!tmp)
+ continue;
+
+ idp = silc_id_payload_parse_data(tmp, len);
+ if (!idp) {
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return FALSE;
+ }
+
+ id = silc_id_payload_get_id(idp);
+
+ switch (silc_id_payload_get_type(idp)) {
+
+ case SILC_ID_CLIENT:
+ entry = (void *)silc_idlist_find_client_by_id(server->local_list,
+ id, TRUE, NULL);
+ if (!entry && check_global)
+ entry = (void *)silc_idlist_find_client_by_id(server->global_list,
+ id, TRUE, NULL);
+ if (entry) {
+ *clients = silc_realloc(*clients, sizeof(**clients) *
+ (*clients_count + 1));
+ (*clients)[(*clients_count)++] = (SilcClientEntry)entry;
+ } else {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, tmp, len);
+ error = TRUE;
+ }
+
+ break;
+
+ case SILC_ID_SERVER:
+ entry = (void *)silc_idlist_find_server_by_id(server->local_list,
+ id, TRUE, NULL);
+ if (!entry && check_global)
+ entry = (void *)silc_idlist_find_server_by_id(server->global_list,
+ id, TRUE, NULL);
+ if (entry) {
+ *servers = silc_realloc(*servers, sizeof(**servers) *
+ (*servers_count + 1));
+ (*servers)[(*servers_count)++] = (SilcServerEntry)entry;
+ } else {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
+ 2, tmp, len);
+ error = TRUE;
+ }
+ break;
+
+ case SILC_ID_CHANNEL:
+ entry = (void *)silc_idlist_find_channel_by_id(server->local_list,
+ id, NULL);
+ if (!entry && check_global)
+ entry = (void *)silc_idlist_find_channel_by_id(server->global_list,
+ id, NULL);
+ if (entry) {
+ *channels = silc_realloc(*channels, sizeof(**channels) *
+ (*channels_count + 1));
+ (*channels)[(*channels_count)++] = (SilcChannelEntry)entry;
+ } else {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
+ 2, tmp, len);
+ error = TRUE;
+ }
+ break;
+ }
+
+ silc_free(id);
+ }
+ }
+
+ if (error) {
+ silc_free(*clients);
+ silc_free(*servers);
+ silc_free(*channels);
+ return FALSE;
+ }
+
+ /* Get the max count of reply messages allowed */
+ tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
+ if (tmp)
+ *count = atoi(tmp);
+ else
+ *count = 0;
+
+ return TRUE;
+}
+
+/* Checks that all mandatory fields in client entry 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 bool
+silc_server_command_identify_check_client(SilcServerCommandContext cmd,
+ SilcClientEntry *clients,
+ uint32 clients_count)
{
SilcServer server = cmd->server;
- int i;
SilcClientEntry entry;
+ SilcServerResolveContext resolve = NULL, r = NULL;
+ uint32 resolve_count = 0;
+ int i, k;
+ bool no_res = TRUE;
for (i = 0; i < clients_count; i++) {
entry = clients[i];
- if (!entry || entry->data.registered == FALSE)
+ if (!entry || entry->nickname ||
+ !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
+ !entry->router)
continue;
- if (!entry->nickname) {
- SilcBuffer tmpbuf;
- uint16 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),
+ /* We need to resolve this entry since it is not complete */
+
+ if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
+ /* The entry is being resolved (and we are not the resolver) so attach
+ to the command reply and we're done with this one. */
+ silc_server_command_pending(server, SILC_COMMAND_NONE,
+ entry->resolve_cmd_ident,
silc_server_command_destructor,
silc_server_command_identify,
silc_server_command_dup(cmd));
+ no_res = FALSE;
+ } else {
+ if (entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
+ /* We've resolved this and it still is not ready. We'll return
+ and are that this will be handled again after it is resolved. */
+ for (i = 0; i < resolve_count; i++) {
+ for (k = 0; k < r->res_argc; k++)
+ silc_free(r->res_argv[k]);
+ silc_free(r->res_argv);
+ silc_free(r->res_argv_lens);
+ silc_free(r->res_argv_types);
+ }
+ silc_free(resolve);
+ return FALSE;
+ } else {
+ /* We'll resolve this client */
+ SilcBuffer idp;
+
+ r = NULL;
+ for (k = 0; k < resolve_count; k++) {
+ if (resolve[k].router == entry->router) {
+ r = &resolve[k];
+ break;
+ }
+ }
- 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);
+ if (!r) {
+ resolve = silc_realloc(resolve, sizeof(*resolve) *
+ (resolve_count + 1));
+ r = &resolve[resolve_count];
+ memset(r, 0, sizeof(*r));
+ r->router = entry->router;
+ r->ident = ++server->cmd_ident;
+ resolve_count++;
+ }
- silc_buffer_free(tmpbuf);
- return FALSE;
+ r->res_argv = silc_realloc(r->res_argv, sizeof(*r->res_argv) *
+ (r->res_argc + 1));
+ r->res_argv_lens = silc_realloc(r->res_argv_lens,
+ sizeof(*r->res_argv_lens) *
+ (r->res_argc + 1));
+ r->res_argv_types = silc_realloc(r->res_argv_types,
+ sizeof(*r->res_argv_types) *
+ (r->res_argc + 1));
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+ r->res_argv[r->res_argc] = silc_calloc(idp->len,
+ sizeof(**r->res_argv));
+ memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
+ r->res_argv_lens[r->res_argc] = idp->len;
+ r->res_argv_types[r->res_argc] = r->res_argc + 3;
+ r->res_argc++;
+ silc_buffer_free(idp);
+
+ entry->resolve_cmd_ident = r->ident;
+ entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
+ entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
+ }
}
}
- return TRUE;
+ /* Do the resolving */
+ for (i = 0; i < resolve_count; i++) {
+ SilcBuffer res_cmd;
+
+ r = &resolve[i];
+
+ /* Send WHOIS request. We send WHOIS since we're doing the requesting
+ now anyway so make it a good one. */
+ res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
+ r->res_argc, r->res_argv,
+ r->res_argv_lens,
+ r->res_argv_types,
+ r->ident);
+ silc_server_packet_send(server, r->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ res_cmd->data, res_cmd->len, FALSE);
+
+ /* Reprocess this packet after received reply */
+ silc_server_command_pending(server, SILC_COMMAND_WHOIS,
+ r->ident,
+ silc_server_command_destructor,
+ silc_server_command_identify,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+
+ silc_buffer_free(res_cmd);
+ for (k = 0; k < r->res_argc; k++)
+ silc_free(r->res_argv[k]);
+ silc_free(r->res_argv);
+ silc_free(r->res_argv_lens);
+ silc_free(r->res_argv_types);
+ no_res = FALSE;
+ }
+ silc_free(resolve);
+
+ return no_res;
}
static void
silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
SilcClientEntry *clients,
uint32 clients_count,
+ SilcServerEntry *servers,
+ uint32 servers_count,
+ SilcChannelEntry *channels,
+ uint32 channels_count,
int count)
{
SilcServer server = cmd->server;
- char *tmp;
int i, k, len;
SilcBuffer packet, idp;
- SilcClientEntry entry;
SilcCommandStatus status;
uint16 ident = silc_command_get_ident(cmd->payload);
char nh[256], uh[256];
SilcSocketConnection hsock;
- len = 0;
- for (i = 0; i < clients_count; i++)
- if (clients[i]->data.registered)
- len++;
-
status = SILC_STATUS_OK;
- if (len > 1)
- status = SILC_STATUS_LIST_START;
- for (i = 0, k = 0; i < clients_count; i++) {
- entry = clients[i];
+ if (clients) {
+ SilcClientEntry entry;
- if (entry->data.registered == FALSE) {
- if (clients_count == 1) {
+ len = 0;
+ for (i = 0; i < clients_count; i++)
+ if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
+ len++;
+
+ if (len == 0 && clients_count) {
+ entry = clients[0];
+ if (entry->nickname) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, entry->nickname,
+ strlen(entry->nickname));
+ } else {
SilcBuffer idp = silc_id_payload_encode(entry->id, 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);
}
- continue;
+
+ return;
}
- if (k >= 1)
- status = SILC_STATUS_LIST_ITEM;
-
- if (clients_count > 1 && k == clients_count - 1)
- status = SILC_STATUS_LIST_END;
-
- if (count && k - 1 == count)
- status = SILC_STATUS_LIST_END;
-
- if (count && k - 1 > count)
- break;
+ if (len > 1)
+ status = SILC_STATUS_LIST_START;
- /* Send IDENTIFY reply */
- idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
- tmp = silc_argument_get_first_arg(cmd->args, NULL);
-
- memset(uh, 0, sizeof(uh));
- memset(nh, 0, sizeof(nh));
+ for (i = 0, k = 0; i < clients_count; i++) {
+ entry = clients[i];
- strncat(nh, entry->nickname, strlen(entry->nickname));
- if (!strchr(entry->nickname, '@')) {
- strncat(nh, "@", 1);
- if (entry->servername) {
- strncat(nh, entry->servername, strlen(entry->servername));
- } else {
- 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->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+ if (clients_count == 1) {
+ SilcBuffer idp = silc_id_payload_encode(entry->id, 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);
+ }
+ continue;
}
- }
- if (!entry->username) {
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
- status, 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);
- }
+ if (k >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+ if (clients_count > 1 && k == clients_count - 1
+ && !servers_count && !channels_count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 == count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 > count)
+ break;
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
- status, ident, 3,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh),
- 4, uh, strlen(uh));
- }
+ /* Send IDENTIFY reply */
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
- 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);
-
- k++;
- }
-}
-
-static int
-silc_server_command_identify_from_client(SilcServerCommandContext cmd)
-{
- SilcServer server = cmd->server;
- char *nick = NULL, *server_name = NULL;
- int count = 0;
- SilcClientEntry *clients = NULL, entry;
- SilcClientID **client_id = NULL;
- uint32 client_id_count = 0, clients_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;
- uint16 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_destructor,
- silc_server_command_identify,
- 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 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;
+ memset(uh, 0, sizeof(uh));
+ memset(nh, 0, sizeof(nh));
+
+ strncat(nh, entry->nickname, strlen(entry->nickname));
+ if (!strchr(entry->nickname, '@')) {
+ strncat(nh, "@", 1);
+ if (entry->servername) {
+ strncat(nh, entry->servername, strlen(entry->servername));
+ } else {
+ len = entry->router ? strlen(entry->router->server_name) :
+ strlen(server->server_name);
+ strncat(nh, entry->router ? entry->router->server_name :
+ server->server_name, len);
+ }
}
- }
- } else {
- if (!silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients, &clients_count))
- silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients, &clients_count);
- }
-
- /* Check global list as well */
- 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;
+
+ if (!entry->username) {
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, 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,
+ status, ident, 3,
+ 2, idp->data, idp->len,
+ 3, nh, strlen(nh),
+ 4, uh, strlen(uh));
}
- }
- } else {
- if (!silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients, &clients_count))
- silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients, &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_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+ 0, packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
silc_buffer_free(idp);
+
+ k++;
}
- goto out;
}
- /* Check that all mandatory fields are present and request those data
- from the server who owns the client if necessary. */
- if (!silc_server_command_identify_check(cmd, clients, clients_count)) {
- ret = -1;
- goto out;
- }
+ status = (status == SILC_STATUS_LIST_ITEM ?
+ SILC_STATUS_LIST_ITEM : SILC_STATUS_OK);
- /* Send the command reply to the client */
- silc_server_command_identify_send_reply(cmd, clients, clients_count,
- count);
+ if (servers) {
+ SilcServerEntry entry;
- out:
- if (client_id_count) {
- for (i = 0; i < client_id_count; i++)
- silc_free(client_id[i]);
- silc_free(client_id);
+ if (status == SILC_STATUS_OK && servers_count > 1)
+ status = SILC_STATUS_LIST_START;
+
+ for (i = 0, k = 0; i < servers_count; i++) {
+ entry = servers[i];
+
+ if (k >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+ if (servers_count > 1 && k == servers_count - 1 && !channels_count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 == count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 > count)
+ break;
+
+ /* Send IDENTIFY reply */
+ idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
+ if (entry->server_name) {
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 2,
+ 2, idp->data, idp->len,
+ 3, entry->server_name,
+ strlen(entry->server_name));
+ } else {
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 1,
+ 2, idp->data, idp->len);
+ }
+
+ 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);
+
+ k++;
+ }
}
- if (clients)
- silc_free(clients);
- if (nick)
- silc_free(nick);
- if (server_name)
- silc_free(server_name);
- return ret;
+ status = (status == SILC_STATUS_LIST_ITEM ?
+ SILC_STATUS_LIST_ITEM : SILC_STATUS_OK);
+
+ if (channels) {
+ SilcChannelEntry entry;
+
+ if (status == SILC_STATUS_OK && channels_count > 1)
+ status = SILC_STATUS_LIST_START;
+
+ for (i = 0, k = 0; i < channels_count; i++) {
+ entry = channels[i];
+
+ if (k >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+ if (channels_count > 1 && k == channels_count - 1)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 == count)
+ status = SILC_STATUS_LIST_END;
+ if (count && k - 1 > count)
+ break;
+
+ /* Send IDENTIFY reply */
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
+ if (entry->channel_name) {
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 2,
+ 2, idp->data, idp->len,
+ 3, entry->channel_name,
+ strlen(entry->channel_name));
+ } else {
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+ status, ident, 1,
+ 2, idp->data, idp->len);
+ }
+
+ 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);
+
+ k++;
+ }
+ }
}
static int
-silc_server_command_identify_from_server(SilcServerCommandContext cmd)
+silc_server_command_identify_process(SilcServerCommandContext cmd)
{
SilcServer server = cmd->server;
- char *nick = NULL, *server_name = NULL;
- int count = 0;
- SilcClientEntry *clients = NULL, entry;
- SilcClientID **client_id = NULL;
- uint32 client_id_count = 0, clients_count = 0;
- int i, ret = 0;
+ uint32 count = 0;
+ int ret = 0;
+ SilcClientEntry *clients = NULL;
+ SilcServerEntry *servers = NULL;
+ SilcChannelEntry *channels = NULL;
+ uint32 clients_count = 0, servers_count = 0, channels_count = 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;
+ /* 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 (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+ server->server_type == SILC_SERVER && !cmd->pending &&
+ !server->standalone) {
+ SilcBuffer tmpbuf;
+ uint16 old_ident;
- /* Process the command request. Let's search for the requested client and
- send reply to the requesting server. */
+ 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);
- 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 {
- if (!silc_idlist_get_clients_by_hash(server->local_list,
- nick, server->md5hash,
- &clients, &clients_count))
- silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients, &clients_count);
- }
-
- /* If we are router we will check our global list as well. */
- if (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 {
- if (!silc_idlist_get_clients_by_hash(server->global_list,
- nick, server->md5hash,
- &clients, &clients_count))
- silc_idlist_get_clients_by_nickname(server->global_list,
- nick, server_name,
- &clients, &clients_count);
- }
- }
+ /* 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);
- 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);
- }
+ /* 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_destructor,
+ silc_server_command_identify,
+ 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 IDENTIFY request */
+ if (!silc_server_command_identify_parse(cmd,
+ &clients, &clients_count,
+ &servers, &servers_count,
+ &channels, &channels_count,
+ &count))
+ return 0;
+
/* Check that all mandatory fields are present and request those data
from the server who owns the client if necessary. */
- if (!silc_server_command_identify_check(cmd, clients, clients_count)) {
+ if (clients && !silc_server_command_identify_check_client(cmd, clients,
+ clients_count)) {
ret = -1;
goto out;
}
- /* Send the command reply */
- silc_server_command_identify_send_reply(cmd, clients, clients_count, count);
+ /* Send the command reply to the client */
+ silc_server_command_identify_send_reply(cmd,
+ clients, clients_count,
+ servers, servers_count,
+ channels, channels_count,
+ 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_free(clients);
+ silc_free(servers);
+ silc_free(channels);
return ret;
}
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
int ret = 0;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 3328);
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
- ret = silc_server_command_identify_from_client(cmd);
- else if ((cmd->sock->type == SILC_SOCKET_TYPE_SERVER) |
- (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER))
- ret = silc_server_command_identify_from_server(cmd);
+ ret = silc_server_command_identify_process(cmd);
if (!ret)
silc_server_command_free(cmd);
static int silc_server_command_bad_chars(char *nick)
{
- if (strchr(nick, '\\')) return TRUE;
- if (strchr(nick, '\"')) return TRUE;
- if (strchr(nick, '´')) return TRUE;
- if (strchr(nick, '`')) return TRUE;
- if (strchr(nick, '\'')) return TRUE;
- if (strchr(nick, '*')) return TRUE;
- if (strchr(nick, '/')) return TRUE;
- if (strchr(nick, '@')) return TRUE;
+ int i;
+
+ for (i = 0; i < strlen(nick); i++) {
+ if (!isalpha(nick[i]))
+ return TRUE;
+ if (nick[i] == ' ') return TRUE;
+ if (nick[i] == '\\') return TRUE;
+ if (nick[i] == '\"') return TRUE;
+ if (nick[i] == '*') return TRUE;
+ if (nick[i] == '?') return TRUE;
+ if (nick[i] == ',') return TRUE;
+ if (nick[i] == '@') return TRUE;
+ }
return FALSE;
}
SilcClientID *new_id;
char *nick;
uint16 ident = silc_command_get_ident(cmd->payload);
+ int nickfail = 0;
if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_NICK, cmd, 1, 1);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_NICK, cmd, 1, 1);
/* Check nickname */
nick = silc_argument_get_arg_type(cmd->args, 1, NULL);
}
if (strlen(nick) > 128)
- nick[127] = '\0';
+ nick[128] = '\0';
/* Create new Client ID */
- silc_id_create_client_id(cmd->server->id, cmd->server->rng,
- cmd->server->md5hash, nick,
- &new_id);
+ while (!silc_id_create_client_id(cmd->server, cmd->server->id,
+ cmd->server->rng,
+ cmd->server->md5hash, nick,
+ &new_id)) {
+ nickfail++;
+ snprintf(&nick[strlen(nick) - 1], 1, "%d", nickfail);
+ }
/* 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
FALSE : TRUE, client->id,
new_id);
+ oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
/* Remove old cache entry */
silc_idcache_del_by_context(server->local_list->clients, client);
- oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-
/* Free old ID */
- if (client->id)
- silc_free(client->id);
+ silc_free(client->id);
/* Save the nickname as this client is our local client */
- if (client->nickname)
- silc_free(client->nickname);
+ silc_free(client->nickname);
client->nickname = strdup(nick);
client->id = new_id;
SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
uint32 lch_count = 0, gch_count = 0;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LIST, cmd, 0, 2);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 2);
/* Get Channel ID */
tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
uint32 argc, tmp_len;
uint16 ident = silc_command_get_ident(cmd->payload);
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_TOPIC, cmd, 1, 2);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_TOPIC, cmd, 1, 2);
argc = silc_argument_get_arg_num(cmd->args);
uint32 len;
uint16 ident = silc_command_get_ident(cmd->payload);
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 4);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INVITE, cmd, 1, 4);
/* Get Channel ID */
tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
unsigned char *tmp = NULL;
uint32 len = 0;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_QUIT, cmd, 0, 1);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_QUIT, cmd, 0, 1);
if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
q->signoff = tmp ? strdup(tmp) : NULL;
/* We quit the connection with little timeout */
- silc_task_register(server->timeout_queue, sock->sock,
+ silc_schedule_task_add(server->schedule, sock->sock,
silc_server_command_quit_cb, (void *)q,
0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
unsigned char *tmp, *comment;
uint32 tmp_len, tmp_len2;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_KILL, cmd, 1, 2);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 2);
if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
/* Get the client entry */
remote_client = silc_idlist_find_client_by_id(server->local_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
if (!remote_client) {
remote_client = silc_idlist_find_client_by_id(server->global_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
if (!remote_client) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
}
}
- if (remote_client->data.registered == FALSE) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
- goto out;
- }
-
/* Get comment */
comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
if (tmp_len2 > 128)
/* Remove the client entry, If it is locally connected then we will also
disconnect the client here */
- if (remote_client->data.registered && remote_client->connection) {
+ if (remote_client->connection) {
/* Remove locally conneted client */
SilcSocketConnection sock = remote_client->connection;
silc_server_free_client_data(server, sock, remote_client, FALSE, NULL);
SilcServerEntry entry = NULL;
SilcServerID *server_id = NULL;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 0, 2);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 0, 2);
/* Get server name */
dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
if (server_id) {
/* Check whether we have this server cached */
entry = silc_idlist_find_server_by_id(server->local_list,
- server_id, NULL);
+ server_id, TRUE, NULL);
if (!entry) {
entry = silc_idlist_find_server_by_id(server->global_list,
- server_id, NULL);
+ server_id, TRUE, NULL);
if (!entry && server->server_type == SILC_ROUTER) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
SILC_STATUS_ERR_NO_SUCH_SERVER);
}
}
- if ((!dest_server && !server_id) ||
+ /* Some buggy servers has sent request to router about themselves. */
+ if (server->server_type == SILC_ROUTER && cmd->sock->user_data == entry)
+ goto out;
+
+ if ((!dest_server && !server_id && !entry) || (entry &&
+ entry == server->id_entry) ||
(dest_server && !cmd->pending &&
!strncasecmp(dest_server, server->server_name, strlen(dest_server)))) {
/* Send our reply */
/* Check whether we have this server cached */
if (!entry && dest_server) {
entry = silc_idlist_find_server_by_name(server->global_list,
- dest_server, NULL);
+ dest_server, TRUE, NULL);
if (!entry) {
entry = silc_idlist_find_server_by_name(server->local_list,
- dest_server, NULL);
+ dest_server, TRUE, NULL);
}
}
uint32 len;
unsigned char *tmp;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 2);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 1, 2);
/* Get Server ID */
tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
SilcChannelClientEntry chl;
SilcBuffer reply, chidp, clidp, keyp = NULL, user_list, mode_list;
uint16 ident = silc_command_get_ident(cmd->payload);
- char check[512];
+ char check[512], check2[512];
SILC_LOG_DEBUG(("Start"));
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)
- goto out;
+ client = silc_server_get_client_resolve(server, client_id);
+ if (!client) {
+ if (cmd->pending)
+ goto out;
+
+ /* The client info is being resolved. Reprocess this packet after
+ receiving the reply to the query. */
+ silc_server_command_pending(server, SILC_COMMAND_WHOIS,
+ server->cmd_ident, NULL,
+ silc_server_command_join,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ return;
+ }
+
+ cmd->pending = FALSE;
}
/*
* Check channel modes
*/
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
- strncat(check, client->nickname, strlen(client->nickname));
- if (!strchr(client->nickname, '@')) {
- strncat(check, "@", 1);
- strncat(check, server->server_name, strlen(server->server_name));
- }
- strncat(check, "!", 1);
- strncat(check, client->username, strlen(client->username));
- if (!strchr(client->username, '@')) {
- strncat(check, "@", 1);
- strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
- }
+ memset(check, 0, sizeof(check));
+ memset(check2, 0, sizeof(check2));
+ strncat(check, client->nickname, strlen(client->nickname));
+ strncat(check, "!", 1);
+ strncat(check, client->username, strlen(client->username));
+ if (!strchr(client->username, '@')) {
+ strncat(check, "@", 1);
+ strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
+ }
+
+ strncat(check2, client->nickname, strlen(client->nickname));
+ if (!strchr(client->nickname, '@')) {
+ strncat(check2, "@", 1);
+ strncat(check2, server->server_name, strlen(server->server_name));
+ }
+ strncat(check2, "!", 1);
+ strncat(check2, client->username, strlen(client->username));
+ if (!strchr(client->username, '@')) {
+ strncat(check2, "@", 1);
+ strncat(check2, cmd->sock->hostname, strlen(cmd->sock->hostname));
}
/* Check invite list if channel is invite-only channel */
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
- channel->mode & SILC_CHANNEL_MODE_INVITE) {
+ if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
if (!channel->invite_list ||
- !silc_string_match(channel->invite_list, check)) {
+ (!silc_string_match(channel->invite_list, check) &&
+ !silc_string_match(channel->invite_list, check2))) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
SILC_STATUS_ERR_NOT_INVITED);
goto out;
/* Check ban list if it exists. If the client's nickname, server,
username and/or hostname is in the ban list the access to the
channel is denied. */
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && channel->ban_list) {
- if (silc_string_match(channel->ban_list, check)) {
+ if (channel->ban_list) {
+ if (silc_string_match(channel->ban_list, check) ||
+ silc_string_match(channel->ban_list, check2)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
goto out;
/* Generate new channel key as protocol dictates */
if ((!created && silc_hash_table_count(channel->user_list) > 0) ||
!channel->channel_key)
- silc_server_create_channel_key(server, channel, 0);
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
/* Send the channel key. This is broadcasted to the channel but is not
sent to the client who is joining to the channel. */
int created = FALSE;
SilcClientID *client_id;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_JOIN, cmd, 1, 4);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 1, 4);
/* Get channel name */
tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
if (silc_server_command_bad_chars(channel_name) == TRUE) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
SILC_STATUS_ERR_BAD_CHANNEL);
- silc_free(channel_name);
goto out;
}
if (server->server_type == SILC_SERVER) {
SilcBuffer tmpbuf;
uint16 old_ident;
+
+ /* If this is pending command callback then we've resolved
+ it and it didn't work, return since we've notified the
+ client already in the command reply callback. */
+ if (cmd->pending)
+ goto out;
old_ident = silc_command_get_ident(cmd->payload);
silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
uint32 motd_len;
uint16 ident = silc_command_get_ident(cmd->payload);
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 1);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_MOTD, cmd, 1, 1);
/* Get server name */
dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
/* Check whether we have this server cached */
entry = silc_idlist_find_server_by_name(server->global_list,
- dest_server, NULL);
+ dest_server, TRUE, NULL);
if (!entry) {
entry = silc_idlist_find_server_by_name(server->local_list,
- dest_server, NULL);
+ dest_server, TRUE, NULL);
}
if (server->server_type == SILC_ROUTER && !cmd->pending &&
if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_UMODE, cmd, 2, 2);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_UMODE, cmd, 2, 2);
/* Get the client's mode mask */
tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
uint32 mode_mask, tmp_len, tmp_len2;
uint16 ident = silc_command_get_ident(cmd->payload);
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CMODE, cmd, 2, 7);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 2, 7);
/* Get Channel ID */
tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
anymore after this. */
/* Re-generate channel key */
- silc_server_create_channel_key(server, channel, 0);
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
/* Send the channel key. This sends it to our local clients and if
we are normal server to our router as well. */
}
/* Re-generate channel key */
- silc_server_create_channel_key(server, channel, 0);
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
/* Send the channel key. This sends it to our local clients and if
we are normal server to our router as well. */
/* Delete old cipher and allocate default one */
silc_cipher_free(channel->channel_key);
- if (!silc_cipher_alloc(cipher ? cipher : "aes-256-cbc",
+ if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER,
&channel->channel_key)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
}
/* Re-generate channel key */
- silc_server_create_channel_key(server, channel, 0);
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
/* Send the channel key. This sends it to our local clients and if
we are normal server to our router as well. */
/* Delete old hmac and allocate default one */
silc_hmac_free(channel->hmac);
- if (!silc_hmac_alloc(hmac ? hmac : "hmac-sha1-96", NULL,
+ if (!silc_hmac_alloc(hmac ? hmac : SILC_DEFAULT_HMAC, NULL,
&channel->hmac)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
silc_calloc(tmp_len + 1, sizeof(*channel->founder_passwd));
memcpy(channel->founder_passwd, tmp, tmp_len);
channel->founder_passwd_len = tmp_len;
+ } else {
+ /* Verify the payload before setting the mode */
+ if (!silc_auth_verify(auth, channel->founder_method,
+ channel->founder_key, 0, idata->hash,
+ client->id, SILC_ID_CLIENT)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_AUTH_FAILED);
+ goto out;
+ }
}
silc_auth_payload_free(auth);
/* Send command reply to sender */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
- SILC_STATUS_OK, ident, 1,
- 2, tmp_mask, 4);
+ SILC_STATUS_OK, ident, 2,
+ 2, tmp_id, tmp_len2,
+ 3, tmp_mask, 4);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
int notify = FALSE;
uint16 ident = silc_command_get_ident(cmd->payload);
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 4);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CUMODE, cmd, 3, 4);
/* Get Channel ID */
tmp_ch_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_ch_len);
/* Get target client's entry */
target_client = silc_idlist_find_client_by_id(server->local_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
if (!target_client) {
target_client = silc_idlist_find_client_by_id(server->global_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
}
if (target_client != client &&
/* Send command reply to sender */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
- SILC_STATUS_OK, ident, 2,
+ SILC_STATUS_OK, ident, 3,
2, tmp_mask, 4,
- 3, tmp_id, tmp_len);
+ 3, tmp_ch_id, tmp_ch_len,
+ 4, tmp_id, tmp_len);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
uint32 tmp_len;
unsigned char *tmp, *comment;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 3);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 3);
/* Get Channel ID */
tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
/* Get target client's entry */
target_client = silc_idlist_find_client_by_id(server->local_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
if (!target_client) {
target_client = silc_idlist_find_client_by_id(server->global_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
}
/* Check that the target client is not channel founder. Channel founder
if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
/* Re-generate channel key */
- silc_server_create_channel_key(server, channel, 0);
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
/* Send the channel key to the channel. The key of course is not sent
to the client who was kicked off the channel. */
SilcServerConfigSectionAdminConnection *admin;
SilcIDListData idata = (SilcIDListData)client;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_OPER, cmd, 1, 2);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_OPER, cmd, 1, 2);
if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
SilcServerConfigSectionAdminConnection *admin;
SilcIDListData idata = (SilcIDListData)client;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SILCOPER, cmd, 1, 2);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SILCOPER, cmd, 1, 2);
- if (server->server_type == SILC_SERVER)
+ if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
- if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ if (server->server_type == SILC_SERVER) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_SILCOPER,
+ SILC_STATUS_ERR_AUTH_FAILED);
goto out;
+ }
/* Get the username */
username = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
uint32 tmp_len;
uint32 port = SILC_PORT;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CONNECT, cmd, 1, 2);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CONNECT, cmd, 1, 2);
if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_BAN, cmd, 0, 3);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_BAN, cmd, 0, 3);
/* Get Channel ID */
id = silc_argument_get_arg_type(cmd->args, 1, &id_len);
unsigned char *name;
uint32 port = SILC_PORT;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CLOSE, cmd, 1, 2);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CLOSE, cmd, 1, 2);
if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
SILC_GET32_MSB(port, tmp);
server_entry = silc_idlist_find_server_by_conn(server->local_list,
- name, port, NULL);
+ name, port, FALSE, NULL);
if (!server_entry) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
SILC_STATUS_ERR_NO_SERVER_ID);
SilcServer server = cmd->server;
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_SHUTDOWN, cmd, 0, 0);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SHUTDOWN, cmd, 0, 0);
if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
goto out;
uint32 len;
unsigned char *tmp;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 2);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 2);
/* Get Channel ID */
tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
/* Re-generate channel key */
- silc_server_create_channel_key(server, channel, 0);
+ if (!silc_server_create_channel_key(server, channel, 0))
+ goto out;
/* Send the channel key */
silc_server_send_channel_key(server, NULL, channel,
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcChannelEntry channel;
- SilcChannelID *id;
- SilcBuffer packet;
+ SilcChannelID *id = NULL;
+ SilcBuffer packet, idp;
unsigned char *channel_id;
uint32 channel_id_len;
SilcBuffer client_id_list;
unsigned char lc[4];
uint32 list_count = 0;
uint16 ident = silc_command_get_ident(cmd->payload);
+ char *channel_name;
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 1);
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_USERS, cmd, 1, 2);
/* Get Channel ID */
channel_id = silc_argument_get_arg_type(cmd->args, 1, &channel_id_len);
- if (!channel_id) {
+
+ /* Get channel name */
+ channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
+
+ if (!channel_id && !channel_name) {
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;
+
+ if (channel_id) {
+ 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;
+ }
}
/* 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 (id)
+ channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
+ else
+ channel = silc_idlist_find_channel_by_name(server->local_list,
+ channel_name, NULL);
+
if (!channel) {
if (server->server_type == SILC_SERVER && !server->standalone &&
!cmd->pending) {
return;
}
- /* We are router and we will check the global list as well. */
- channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
+ /* Check the global list as well. */
+ if (id)
+ channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
+ else
+ channel = silc_idlist_find_channel_by_name(server->global_list,
+ channel_name, NULL);
if (!channel) {
/* Channel really does not exist */
silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
}
}
+ /* If the channel is private or secret do not send anything, unless the
+ user requesting this command is on the channel. */
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+ if (channel->mode & (SILC_CHANNEL_MODE_PRIVATE | SILC_CHANNEL_MODE_SECRET)
+ && !silc_server_client_on_channel(cmd->sock->user_data, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
+ } else {
+ if (channel->mode &
+ (SILC_CHANNEL_MODE_PRIVATE | SILC_CHANNEL_MODE_SECRET)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
+ }
+
/* Get the users list */
silc_server_get_users_on_channel(server, channel, &client_id_list,
&client_mode_list, &list_count);
SILC_PUT32_MSB(list_count, lc);
/* Send reply */
+ idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
SILC_STATUS_OK, ident, 4,
- 2, channel_id, channel_id_len,
+ 2, idp->data, idp->len,
3, lc, 4,
4, client_id_list->data,
client_id_list->len,
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
+ silc_buffer_free(idp);
silc_buffer_free(packet);
silc_buffer_free(client_id_list);
silc_buffer_free(client_mode_list);
- silc_free(id);
+ if (id)
+ silc_free(id);
out:
silc_server_command_free(cmd);
SilcServerID *server_id = NULL;
SilcIDPayload idp = NULL;
uint16 ident = silc_command_get_ident(cmd->payload);
- unsigned char *tmp;
- uint32 tmp_len;
- SilcBuffer pk;
+ unsigned char *tmp, *pkdata;
+ uint32 tmp_len, pklen;
+ SilcBuffer pk = NULL;
SilcIdType id_type;
SILC_LOG_DEBUG(("Start"));
/* If the client is not found from local list there is no chance it
would be locally connected client so send the command further. */
client = silc_idlist_find_client_by_id(server->local_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
if (!client)
client = silc_idlist_find_client_by_id(server->global_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
if ((!client && !cmd->pending && !server->standalone) ||
- (client && !client->connection && !cmd->pending &&
- !server->standalone) ||
- (client && !client->data.public_key && !cmd->pending &&
- !server->standalone)) {
+ (client && !client->connection && !cmd->pending) ||
+ (client && !client->data.public_key && !cmd->pending)) {
SilcBuffer tmpbuf;
uint16 old_ident;
SilcSocketConnection dest_sock;
return;
}
- if (!client && cmd->pending) {
+ if (!client) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
goto out;
}
/* The client is locally connected, just get the public key and
- send it back. */
- tmp = silc_pkcs_public_key_encode(client->data.public_key, &tmp_len);
- pk = silc_buffer_alloc(4 + tmp_len);
- silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
- silc_buffer_format(pk,
- SILC_STR_UI_SHORT(tmp_len),
- SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
- SILC_STR_UI_XNSTRING(tmp, tmp_len),
- SILC_STR_END);
- silc_free(tmp);
-
+ send it back. If they key does not exist then do not send it,
+ send just OK reply */
+ if (!client->data.public_key) {
+ pkdata = NULL;
+ pklen = 0;
+ } else {
+ tmp = silc_pkcs_public_key_encode(client->data.public_key, &tmp_len);
+ pk = silc_buffer_alloc(4 + tmp_len);
+ silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
+ silc_buffer_format(pk,
+ SILC_STR_UI_SHORT(tmp_len),
+ SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
+ SILC_STR_UI_XNSTRING(tmp, tmp_len),
+ SILC_STR_END);
+ silc_free(tmp);
+ pkdata = pk->data;
+ pklen = pk->len;
+ }
} else if (id_type == SILC_ID_SERVER) {
server_id = silc_id_payload_get_id(idp);
/* If the server is not found from local list there is no chance it
would be locally connected server so send the command further. */
server_entry = silc_idlist_find_server_by_id(server->local_list,
- server_id, NULL);
+ server_id, TRUE, NULL);
if (!server_entry)
server_entry = silc_idlist_find_server_by_id(server->global_list,
- server_id, NULL);
+ server_id, TRUE, NULL);
- if ((!server_entry && !cmd->pending && !server->standalone) ||
- (server_entry && !server_entry->connection && !cmd->pending &&
- !server->standalone) ||
- (server_entry && !server_entry->data.public_key && !cmd->pending &&
- !server->standalone)) {
+ if (server_entry != server->id_entry &&
+ ((!server_entry && !cmd->pending && !server->standalone) ||
+ (server_entry && !server_entry->connection && !cmd->pending &&
+ !server->standalone) ||
+ (server_entry && !server_entry->data.public_key && !cmd->pending &&
+ !server->standalone))) {
SilcBuffer tmpbuf;
uint16 old_ident;
return;
}
- if (!server_entry && cmd->pending) {
+ if (!server_entry) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
goto out;
}
- /* The client is locally connected, just get the public key and
- send it back. */
- tmp = silc_pkcs_public_key_encode(server_entry->data.public_key, &tmp_len);
- pk = silc_buffer_alloc(4 + tmp_len);
- silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
- silc_buffer_format(pk,
- SILC_STR_UI_SHORT(tmp_len),
- SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
- SILC_STR_UI_XNSTRING(tmp, tmp_len),
- SILC_STR_END);
- silc_free(tmp);
+ /* If they key does not exist then do not send it, send just OK reply */
+ if (!server_entry->data.public_key) {
+ pkdata = NULL;
+ pklen = 0;
+ } else {
+ tmp = silc_pkcs_public_key_encode(server_entry->data.public_key,
+ &tmp_len);
+ pk = silc_buffer_alloc(4 + tmp_len);
+ silc_buffer_pull_tail(pk, SILC_BUFFER_END(pk));
+ silc_buffer_format(pk,
+ SILC_STR_UI_SHORT(tmp_len),
+ SILC_STR_UI_SHORT(SILC_SKE_PK_TYPE_SILC),
+ SILC_STR_UI_XNSTRING(tmp, tmp_len),
+ SILC_STR_END);
+ silc_free(tmp);
+ pkdata = pk->data;
+ pklen = pk->len;
+ }
} else {
goto out;
}
tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_GETKEY,
- SILC_STATUS_OK, ident, 2,
+ SILC_STATUS_OK, ident,
+ pkdata ? 2 : 1,
2, tmp, tmp_len,
- 3, pk->data, pk->len);
+ 3, pkdata, pklen);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
silc_buffer_free(packet);
- silc_buffer_free(pk);
+
+ if (pk)
+ silc_buffer_free(pk);
out:
if (idp)