From d49df393e2b491ff855621e3011d7aa769543df0 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Thu, 19 Sep 2002 11:58:40 +0000 Subject: [PATCH] Renamed silc_server_get_client_resolve to silc_server_query_client, added server_query.[ch]. --- apps/silcd/Makefile.am | 1 + apps/silcd/command.c | 16 +- apps/silcd/packet_receive.c | 6 +- apps/silcd/server.c | 55 --- apps/silcd/server.h | 4 - apps/silcd/server_query.c | 679 ++++++++++++++++++++++++++++++++++++ apps/silcd/server_query.h | 46 +++ apps/silcd/serverincludes.h | 1 + 8 files changed, 737 insertions(+), 71 deletions(-) create mode 100644 apps/silcd/server_query.c create mode 100644 apps/silcd/server_query.h diff --git a/apps/silcd/Makefile.am b/apps/silcd/Makefile.am index 3322c946..f0c3d8fe 100644 --- a/apps/silcd/Makefile.am +++ b/apps/silcd/Makefile.am @@ -33,6 +33,7 @@ silcd_SOURCES = \ server_util.c \ server_backup.c \ serverconfig.c \ + server_query.c \ serverid.c \ server_version.c diff --git a/apps/silcd/command.c b/apps/silcd/command.c index d5353d81..eba9368c 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -8,8 +8,7 @@ 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -1182,11 +1181,10 @@ silc_server_command_whois_process(SilcServerCommandContext cmd) SILC_SERVER_CMD_FUNC(whois) { SilcServerCommandContext cmd = (SilcServerCommandContext)context; - int ret = 0; - SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 3328); + SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOIS, cmd, 1, 256); - ret = silc_server_command_whois_process(cmd); + silc_server_command_whois_process(cmd); silc_server_command_free(cmd); } @@ -2183,7 +2181,7 @@ SILC_SERVER_CMD_FUNC(identify) SilcServerCommandContext cmd = (SilcServerCommandContext)context; int ret = 0; - SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 3328); + SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_IDENTIFY, cmd, 1, 256); ret = silc_server_command_identify_process(cmd); silc_server_command_free(cmd); @@ -2693,7 +2691,7 @@ SILC_SERVER_CMD_FUNC(invite) } /* Get the client entry */ - dest = silc_server_get_client_resolve(server, dest_id, FALSE, &resolve); + dest = silc_server_query_client(server, dest_id, FALSE, &resolve); if (!dest) { if (server->server_type != SILC_SERVER || !resolve) { silc_server_command_send_status_reply( @@ -3325,8 +3323,8 @@ static void silc_server_command_join_channel(SilcServer server, if (!client) return; } else { - client = silc_server_get_client_resolve(server, client_id, FALSE, - &resolve); + client = silc_server_query_client(server, client_id, FALSE, + &resolve); if (!client) { if (cmd->pending) goto out; diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index bb362fe8..4589ab7c 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -3463,8 +3463,8 @@ void silc_server_resume_client(SilcServer server, idata = (SilcIDListData)client; /* Get entry to the client, and resolve it if we don't have it. */ - detached_client = silc_server_get_client_resolve(server, client_id, FALSE, - &resolved); + detached_client = silc_server_query_client(server, client_id, FALSE, + &resolved); if (!detached_client) { if (resolved) { /* The client info is being resolved. Reprocess this packet after @@ -3508,7 +3508,7 @@ void silc_server_resume_client(SilcServer server, /* The client info is being resolved. Reprocess this packet after receiving the reply to the query. */ SILC_LOG_DEBUG(("Resolving client info")); - silc_server_get_client_resolve(server, client_id, TRUE, NULL); + silc_server_query_client(server, client_id, TRUE, NULL); r = silc_calloc(1, sizeof(*r)); if (!r) return; diff --git a/apps/silcd/server.c b/apps/silcd/server.c index fa1d8d25..6c8156c0 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -4935,61 +4935,6 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server, return buffer; } -/* Finds client entry by Client ID and if it is not found then resolves - it using WHOIS command. */ - -SilcClientEntry silc_server_get_client_resolve(SilcServer server, - SilcClientID *client_id, - bool always_resolve, - bool *resolved) -{ - SilcClientEntry client; - - if (resolved) - *resolved = FALSE; - - client = silc_idlist_find_client_by_id(server->local_list, client_id, - TRUE, NULL); - if (!client) { - client = silc_idlist_find_client_by_id(server->global_list, - client_id, TRUE, NULL); - if (!client && server->server_type == SILC_ROUTER) - return NULL; - } - - if (!client && server->standalone) - return NULL; - - if (!client || !client->nickname || !client->username || - always_resolve) { - SilcBuffer buffer, idp; - - if (client) { - client->data.status |= SILC_IDLIST_STATUS_RESOLVING; - client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED; - client->resolve_cmd_ident = ++server->cmd_ident; - } - - idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT); - buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS, - server->cmd_ident, 1, - 4, idp->data, idp->len); - silc_server_packet_send(server, client ? client->router->connection : - SILC_PRIMARY_ROUTE(server), - SILC_PACKET_COMMAND, 0, - buffer->data, buffer->len, FALSE); - silc_buffer_free(idp); - silc_buffer_free(buffer); - - if (resolved) - *resolved = TRUE; - - return NULL; - } - - return client; -} - /* A timeout callback for the re-key. We will be the initiator of the re-key protocol. */ diff --git a/apps/silcd/server.h b/apps/silcd/server.h index 5757fefc..7694b528 100644 --- a/apps/silcd/server.h +++ b/apps/silcd/server.h @@ -233,10 +233,6 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server, bool get_private, bool get_secret, SilcBuffer *user_mode_list); -SilcClientEntry silc_server_get_client_resolve(SilcServer server, - SilcClientID *client_id, - bool always_resolve, - bool *resolved); void silc_server_stderr(char *message); #endif diff --git a/apps/silcd/server_query.c b/apps/silcd/server_query.c new file mode 100644 index 00000000..f285baa2 --- /dev/null +++ b/apps/silcd/server_query.c @@ -0,0 +1,679 @@ +/* + + server_query.c + + Author: Pekka Riikonen + + Copyright (C) 2002 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ +/* $Id$ */ + +#include "serverincludes.h" +#include "server_internal.h" + +typedef struct { + void *id; + SilcIdType id_type; +} *SilcServerQueryID; + +typedef struct { + SilcUInt32 index; /* Index to IDs */ + bool from_cmd; /* TRUE if `index' is from command args, + otherwise from query->ids */ + SilcStatus error; /* The actual error */ +} *SilcServerQueryError; + +typedef struct { + SilcCommand querycmd; /* Query command */ + SilcServerCommandContext cmd; /* Command context for query */ + + char *nickname; /* Queried nickname */ + char *nick_server; /* Queried nickname's server */ + char *server_name; /* Queried server name */ + char *channel_name; /* Queried channel name */ + SilcServerQueryID ids; /* Queried IDs */ + SilcUInt32 ids_count; /* number of queried IDs */ + SilcUInt32 reply_count; /* Requested reply count */ + SilcDList attrs; /* Requested Attributes in WHOIS */ + + SilcServerQueryError errors; /* Query errors */ + SilcUInt32 errors_count; /* number of errors */ +} *SilcServerQuery; + +void silc_server_query_free(SilcServerQuery query); +bool silc_server_query_check_error(SilcServer server, + SilcServerQuery query, + SilcServerCommandReplyContext cmdr); +void silc_server_query_send_error(SilcServer server, + SilcServerQuery query, + SilcStatus error, ...); +void silc_server_query_add_error(SilcServer server, + SilcServerQuery query, + bool from_cmd, + SilcUInt32 index, + SilcStatus error); +void silc_server_query_send_router(SilcServer server, SilcServerQuery query); +void silc_server_query_send_router_reply(void *context, void *reply); +void silc_server_query_parse(SilcServer server, SilcServerQuery query); +void silc_server_query_process(SilcServer server, SilcServerQuery query); + + +/* Free the query context structure and all allocated resources. */ + +void silc_server_query_free(SilcServerQuery query) +{ + int i; + + silc_server_command_free(query->cmd); + + silc_free(query->nickname); + silc_free(query->nick_server); + silc_free(query->server_name); + silc_free(query->channel_name); + + for (i = 0; i < query->ids_count; i++) + silc_free(query->ids[i].id); + silc_free(query->ids); + + if (query->attrs) + silc_attribute_payload_list_free(query->attrs); + + silc_free(query->errors); + + memset(query, 'F', sizeof(*query)); + silc_free(query); +} + +/* Check whether command reply contained error, and reply the error to + the original sender if it occurred. */ + +bool silc_server_query_check_error(SilcServer server, + SilcServerQuery query, + SilcServerCommandReplyContext cmdr) +{ + if (!cmdr) + return FALSE; + + if (!silc_command_get_status(cmdr->payload, NULL, NULL)) { + SilcBuffer buffer; + + /* Send the same command reply payload which contains the error */ + silc_command_set_command(cmdr->payload, query->querycmd); + silc_command_set_ident(cmdr->payload, + silc_command_get_ident(query->cmd->payload)); + buffer = silc_command_payload_encode_payload(cmdr->payload); + silc_server_packet_send(server, query->cmd->sock, + SILC_PACKET_COMMAND_REPLY, 0, + buffer->data, buffer->len, FALSE); + silc_buffer_free(buffer); + return TRUE; + } + + return FALSE; +} + +/* Send error reply indicated by the `error' to the original sender of + the query. */ + +void silc_server_query_send_error(SilcServer server, + SilcServerQuery query, + SilcStatus error, ...) +{ + va_list va; + SilcBuffer packet; + unsigned char *data = NULL; + SilcUInt32 data_len = 0, data_type = 0, argc = 0; + + va_start(va, error); + data_type = va_arg(va, SilcUInt32); + if (data_type) { + argc = 1; + data = va_arg(va, unsigned char *); + data_len = va_arg(va, SilcUInt32); + } + + /* Send the command reply with error */ + packet = silc_command_reply_payload_encode_va( + query->querycmd, error, 0, + silc_command_get_ident(query->cmd->payload), + argc, data_type, data, data_len); + silc_server_packet_send(server, query->cmd->sock, + SILC_PACKET_COMMAND_REPLY, 0, + packet->data, packet->len, FALSE); + + silc_buffer_free(packet); + va_end(va); +} + +/* Add error to error list. Multiple errors may occur during the query + processing and this function can be used to add one error. The + `type_index' is the index to the command context which includes the + argument which caused the error. */ + +void silc_server_query_add_error(SilcServer server, + SilcServerQuery query, + bool from_cmd, + SilcUInt32 index, + SilcStatus error) +{ + query->errors = silc_realloc(query->errors, sizeof(*query->errors) * + (query->errors_count + 1)); + if (!query->errors) + return; + query->errors[query->errors_count].index = index; + query->errors[query->errors_count].from_cmd = from_cmd; + query->errors[query->errors_count].error = error; + query->errors_count++; +} + +/* Processes query as command. The `query' is the command that is + being processed indicated by the `cmd'. The `query' can be one of + the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or + SILC_COMMAND_IDENTIFY. This function handles the reply sending + to the entity who sent this query to us automatically. Returns + TRUE if the query is being processed or FALSE on error. */ + +bool silc_server_query_command(SilcServer server, SilcCommand querycmd, + SilcServerCommandContext cmd) +{ + SilcServerQuery query; + + switch (querycmd) { + + case SILC_COMMAND_WHOIS: + { + query = silc_calloc(1, sizeof(*query)); + query->querycmd = querycmd; + query->cmd = silc_server_command_dup(cmd); + + /* If we are normal server and query contains nickname, send it + directly to router. */ + if (server->server_type == SILC_SERVER && !server->standalone && + silc_argument_get_arg_type(cmd->args, 1, NULL)) { + silc_server_query_send_router(server, query); + break; + } + + /* Now parse the WHOIS query */ + silc_server_query_parse(server, query); + } + break; + + case SILC_COMMAND_WHOWAS: + { + query = silc_calloc(1, sizeof(*query)); + query->querycmd = querycmd; + query->cmd = silc_server_command_dup(cmd); + + /* WHOWAS query is always sent to router if we are normal server */ + if (server->server_type == SILC_SERVER && !server->standalone) { + silc_server_query_send_router(server, query); + break; + } + + /* Now parse the WHOWAS query */ + silc_server_query_parse(server, query); + } + break; + + case SILC_COMMAND_IDENTIFY: + { + query = silc_calloc(1, sizeof(*query)); + query->querycmd = querycmd; + query->cmd = silc_server_command_dup(cmd); + + /* If we are normal server and query does not contain IDs, send it + directly to router (it contains nickname, server name or channel + name). */ + if (server->server_type == SILC_SERVER && !server->standalone && + !silc_argument_get_arg_type(cmd->args, 5, NULL)) { + silc_server_query_send_router(server, query); + break; + } + + /* Now parse the IDENTIFY query */ + silc_server_query_parse(server, query); + } + break; + + default: + SILC_LOG_ERROR(("Bad query using %d command", querycmd)); + return FALSE; + } + + return TRUE; +} + +/* Send the received query to our primary router since we could not + handle the query directly. We will reprocess the query after our + router replies back. */ + +void silc_server_query_send_router(SilcServer server, SilcServerQuery query) +{ + SilcBuffer tmpbuf; + SilcUInt16 old_ident; + + /* Send WHOIS command to our router */ + old_ident = silc_command_get_ident(query->cmd->payload); + silc_command_set_ident(query->cmd->payload, ++server->cmd_ident); + tmpbuf = silc_command_payload_encode_payload(query->cmd->payload); + silc_server_packet_send(server, + SILC_PRIMARY_ROUTE(server), + SILC_PACKET_COMMAND, 0, + tmpbuf->data, tmpbuf->len, TRUE); + silc_command_set_ident(query->cmd->payload, old_ident); + silc_buffer_free(tmpbuf); + + /* Continue parsing the query after received reply from router */ + silc_server_command_pending(server, query->querycmd, server->cmd_ident, + silc_server_query_send_router_reply, query); +} + +/* Reply callback called after primary router has replied to our initial + sending of the query to it. We will proceed the query in this function. */ + +void silc_server_query_send_router_reply(void *context, void *reply) +{ + SilcServerQuery query = context; + SilcServer server = query->cmd->server; + + /* Check if router sent error reply */ + if (!silc_server_query_check_error(server, query, reply)) { + silc_server_query_free(query); + return; + } + + /* Continue with parsing */ + silc_server_query_parse(server, query); +} + +/* Parse the command query and start processing the queries in detail. */ + +void silc_server_query_parse(SilcServer server, SilcServerQuery query) +{ + SilcServerCommandContext cmd = query->cmd; + unsigned char *tmp; + SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args); + void *id; + SilcIdType id_type; + int i; + + switch (query->querycmd) { + + case SILC_COMMAND_WHOIS: + { + /* Get Client IDs if present. Take IDs always instead of nickname. */ + tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len); + if (!tmp) { + + /* Get nickname */ + tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len); + if (!tmp) { + silc_server_query_send_error(server, query, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0); + silc_server_query_free(query); + return; + } + + /* Get the nickname@server string and parse it */ + if (!silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) { + silc_server_query_send_error(server, query, + SILC_STATUS_ERR_BAD_NICKNAME, 0); + silc_server_query_free(query); + return; + } + + } else { + /* Parse the IDs included in the query */ + query->ids = silc_calloc(argc, sizeof(*query->ids)); + + for (i = 0; i < argc; i++) { + tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len); + if (!tmp) + continue; + + id = silc_id_payload_parse_id(tmp, tmp_len, NULL); + if (!id) { + silc_server_query_add_error(server, query, TRUE, i + 4, + SILC_STATUS_ERR_BAD_CLIENT_ID); + continue; + } + + query->ids[query->ids_count].id = id; + query->ids[query->ids_count].id_type = SILC_ID_CLIENT; + query->ids_count++; + } + } + + /* Get the max count of reply messages allowed */ + tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); + if (tmp && tmp_len == sizeof(SilcUInt32)) + SILC_GET32_MSB(query->reply_count, tmp); + + /* Get requested attributes if set */ + tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len); + if (tmp) + query->attrs = silc_attribute_payload_parse_list(tmp, tmp_len); + } + break; + + case SILC_COMMAND_WHOWAS: + { + /* Get nickname */ + tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len); + if (!tmp) { + silc_server_query_send_error(server, query, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0); + silc_server_query_free(query); + return; + } + + /* Get the nickname@server string and parse it */ + if (!silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) { + silc_server_query_send_error(server, query, + SILC_STATUS_ERR_BAD_NICKNAME, 0); + silc_server_query_free(query); + return; + } + + /* Get the max count of reply messages allowed */ + tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); + if (tmp && tmp_len == sizeof(SilcUInt32)) + SILC_GET32_MSB(query->reply_count, tmp); + } + break; + + case SILC_COMMAND_IDENTIFY: + { + /* Get IDs if present. Take IDs always instead of names. */ + tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len); + if (!tmp) { + + /* Try get nickname */ + tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len); + if (tmp) { + /* Get the nickname@server string and parse it */ + if (!silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) + silc_server_query_add_error(server, query, TRUE, 1, + SILC_STATUS_ERR_BAD_NICKNAME); + } + + /* Try get server name */ + tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); + if (tmp) + query->server_name = silc_memdup(tmp, tmp_len); + + /* Get channel name */ + tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len); + if (tmp) + query->channel_name = silc_memdup(tmp, tmp_len); + + } else { + /* Parse the IDs included in the query */ + query->ids = silc_calloc(argc, sizeof(*query->ids)); + + for (i = 0; i < argc; i++) { + tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len); + if (!tmp) + continue; + + id = silc_id_payload_parse_id(tmp, tmp_len, &id_type); + if (!id) { + silc_server_query_add_error(server, query, TRUE, i + 5, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + continue; + } + + query->ids[query->ids_count].id = id; + query->ids[query->ids_count].id_type = id_type; + query->ids_count++; + } + } + + /* Get the max count of reply messages allowed */ + tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len); + if (tmp && tmp_len == sizeof(SilcUInt32)) + SILC_GET32_MSB(query->reply_count, tmp); + } + break; + } + + /* Start processing the query information */ + silc_server_query_process(server, query); +} + +/* Processes the parsed query. This does the actual finding of the + queried information and prepares for sending reply to the original + sender of the query command. It is guaranteed that this function + (which may be slow) is called only once for entire query. */ + +void silc_server_query_process(SilcServer server, SilcServerQuery query) +{ + SilcServerCommandContext cmd = query->cmd; + bool check_global = FALSE; + void *entry; + SilcClientEntry *clients = NULL; + SilcChannelEntry *channels = NULL; + SilcServerEntry *servers = NULL; + SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0; + int i; + + /* Check global lists if query is coming from client or we are not + normal server (we know global information). */ + if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) + check_global = TRUE; + else if (server->server_type != SILC_SERVER) + check_global = TRUE; + + if (query->nickname) { + /* Get all clients matching nickname from local list */ + if (!silc_idlist_get_clients_by_hash(server->local_list, + query->nickname, server->md5hash, + &clients, &clients_count)) + silc_idlist_get_clients_by_nickname(server->local_list, + query->nickname, + query->nick_server, + &clients, &clients_count); + + /* Check global list as well */ + if (check_global) { + if (!silc_idlist_get_clients_by_hash(server->global_list, + query->nickname, server->md5hash, + &clients, &clients_count)) + silc_idlist_get_clients_by_nickname(server->global_list, + query->nickname, + query->nick_server, + &clients, &clients_count); + } + + if (!clients) + silc_server_query_add_error(server, query, TRUE, 1, + SILC_STATUS_ERR_NO_SUCH_NICK); + } + + if (query->server_name) { + /* Find server by name */ + entry = silc_idlist_find_server_by_name(server->local_list, + query->server_name, TRUE, NULL); + if (!entry && check_global) + entry = silc_idlist_find_server_by_name(server->global_list, + query->server_name, TRUE, NULL); + if (entry) { + servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1)); + servers[servers_count++] = (SilcServerEntry)entry; + } + + if (!servers) + silc_server_query_add_error(server, query, TRUE, 2, + SILC_STATUS_ERR_NO_SUCH_SERVER); + } + + if (query->channel_name) { + /* Find channel by name */ + entry = silc_idlist_find_channel_by_name(server->local_list, + query->channel_name, NULL); + if (!entry && check_global) + entry = silc_idlist_find_channel_by_name(server->global_list, + query->channel_name, NULL); + if (entry) { + channels = silc_realloc(channels, sizeof(*channels) * + (channels_count + 1)); + channels[channels_count++] = (SilcChannelEntry)entry; + } + + if (!channels) + silc_server_query_add_error(server, query, TRUE, 3, + SILC_STATUS_ERR_NO_SUCH_CHANNEL); + } + + if (query->ids_count) { + /* Find entries by the queried IDs */ + for (i = 0; i < query->ids_count; i++) { + void *id = query->ids[i].id; + if (!id) + continue; + + switch (query->ids[i].id_type) { + + case SILC_ID_CLIENT: + /* Get client entry */ + entry = silc_idlist_find_client_by_id(server->local_list, + id, TRUE, NULL); + if (!entry && check_global) + entry = silc_idlist_find_client_by_id(server->global_list, + id, TRUE, NULL); + if (!entry) { + silc_server_query_add_error(server, query, FALSE, i, + SILC_STATUS_ERR_NO_SUCH_CLIENT_ID); + continue; + } + + clients = silc_realloc(clients, sizeof(*clients) * + (clients_count + 1)); + clients[clients_count++] = (SilcClientEntry)entry; + break; + + case SILC_ID_SERVER: + /* Get server entry */ + entry = silc_idlist_find_server_by_id(server->local_list, + id, TRUE, NULL); + if (!entry && check_global) + entry = silc_idlist_find_server_by_id(server->global_list, + id, TRUE, NULL); + if (!entry) { + silc_server_query_add_error(server, query, FALSE, i, + SILC_STATUS_ERR_NO_SUCH_SERVER_ID); + continue; + } + + servers = silc_realloc(servers, sizeof(*servers) * + (servers_count + 1)); + servers[servers_count++] = (SilcServerEntry)entry; + break; + + case SILC_ID_CHANNEL: + /* Get channel entry */ + entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL); + if (!entry && check_global) + entry = silc_idlist_find_channel_by_id(server->global_list, id, + NULL); + if (!entry) { + silc_server_query_add_error(server, query, FALSE, i, + SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID); + continue; + } + + channels = silc_realloc(channels, sizeof(*channels) * + (channels_count + 1)); + channels[channels_count++] = (SilcChannelEntry)entry; + break; + + default: + break; + } + } + } + + /* If nothing was found, then just send the errors */ + if (!clients && !channels && !servers) { + + silc_server_query_free(query); + return; + } + + /* Now process all found information and if necessary do some more + querying. */ + +} + +/* Find client by the Client ID indicated by the `client_id', and if not + found then query it by using WHOIS command. The client information + is also resolved if the cached information is incomplete or if the + `always_resolve' is set to TRUE. The indication whether requested + client was being resolved is saved into `resolved'. If the client + is not being resolved its entry is returned by this function. NULL + is returned if client is resolved. */ + +SilcClientEntry silc_server_query_client(SilcServer server, + const SilcClientID *client_id, + bool always_resolve, + bool *resolved) +{ + SilcClientEntry client; + + if (resolved) + *resolved = FALSE; + + client = silc_idlist_find_client_by_id(server->local_list, + (SilcClientID *)client_id, + TRUE, NULL); + if (!client) { + client = silc_idlist_find_client_by_id(server->global_list, + (SilcClientID *)client_id, + TRUE, NULL); + if (!client && server->server_type == SILC_ROUTER) + return NULL; + } + + if (!client && server->standalone) + return NULL; + + if (!client || !client->nickname || !client->username || + always_resolve) { + SilcBuffer buffer, idp; + + if (client) { + client->data.status |= SILC_IDLIST_STATUS_RESOLVING; + client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED; + client->resolve_cmd_ident = ++server->cmd_ident; + } + + idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT); + buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS, + server->cmd_ident, 1, + 4, idp->data, idp->len); + silc_server_packet_send(server, client ? client->router->connection : + SILC_PRIMARY_ROUTE(server), + SILC_PACKET_COMMAND, 0, + buffer->data, buffer->len, FALSE); + silc_buffer_free(idp); + silc_buffer_free(buffer); + + if (resolved) + *resolved = TRUE; + + return NULL; + } + + return client; +} diff --git a/apps/silcd/server_query.h b/apps/silcd/server_query.h new file mode 100644 index 00000000..4c0c8687 --- /dev/null +++ b/apps/silcd/server_query.h @@ -0,0 +1,46 @@ +/* + + server_query.c + + Author: Pekka Riikonen + + Copyright (C) 2002 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#ifndef SERVER_QUERY_H +#define SERVER_QUERY_H + +/* Processes query as command. The `query' is the command that is + being processed indicated by the `cmd'. The `query' can be one of + the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or + SILC_COMMAND_IDENTIFY. This function handles the reply sending + to the entity who sent this query to us automatically. Returns + TRUE if the query is being processed or FALSE on error. */ +bool silc_server_query_command(SilcServer server, SilcCommand querycmd, + SilcServerCommandContext cmd); + +/* Find client by the Client ID indicated by the `client_id', and if not + found then query it by using WHOIS command. The client information + is also resolved if the cached information is incomplete or if the + `always_resolve' is set to TRUE. The indication whether requested + client was being resolved is saved into `resolved'. If the client + is not being resolved its entry is returned by this function. NULL + is returned if client is resolved. If the client was resovled the + caller may attach to the query by using silc_server_command_pending + function. The server->cmd_ident includes the query identifier. */ +SilcClientEntry silc_server_query_client(SilcServer server, + const SilcClientID *client_id, + bool always_resolve, + bool *resolved); + +#endif /* SERVER_QUERY_H */ diff --git a/apps/silcd/serverincludes.h b/apps/silcd/serverincludes.h index accbba71..fede3316 100644 --- a/apps/silcd/serverincludes.h +++ b/apps/silcd/serverincludes.h @@ -41,6 +41,7 @@ typedef struct SilcServerStruct *SilcServer; #include "protocol.h" #include "command.h" #include "command_reply.h" +#include "server_query.h" #include "silcd.h" #include "server_backup.h" -- 2.24.0