- unsigned char *tmp;
- SilcUInt32 len;
-
- tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
- if (!tmp) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOWAS,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
- 0);
- return FALSE;
- }
-
- /* Get the nickname@server string and parse it. */
- 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)
- SILC_GET32_MSB(*count, tmp);
- else
- *count = 0;
-
- return TRUE;
-}
-
-static char
-silc_server_command_whowas_check(SilcServerCommandContext cmd,
- SilcClientEntry *clients,
- SilcUInt32 clients_count)
-{
- SilcServer server = cmd->server;
- int i;
- SilcClientEntry entry;
-
- for (i = 0; i < clients_count; i++) {
- entry = clients[i];
-
- if (!entry->nickname || !entry->username) {
- SilcBuffer tmpbuf;
- SilcUInt16 old_ident;
-
- if (!entry->router)
- continue;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, ++server->cmd_ident);
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- /* Send WHOWAS 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_WHOWAS,
- silc_command_get_ident(cmd->payload),
- silc_server_command_whowas,
- silc_server_command_dup(cmd));
- cmd->pending = TRUE;
- silc_command_set_ident(cmd->payload, old_ident);
-
- silc_buffer_free(tmpbuf);
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-static void
-silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
- SilcClientEntry *clients,
- SilcUInt32 clients_count)
-{
- SilcServer server = cmd->server;
- char *tmp;
- int i, k, count = 0, len;
- SilcBuffer packet, idp;
- SilcClientEntry entry = NULL;
- SilcStatus status;
- SilcUInt16 ident = silc_command_get_ident(cmd->payload);
- char nh[256], uh[256];
- int valid_count;
-
- status = SILC_STATUS_OK;
-
- /* Process only entries that are not registered anymore. */
- valid_count = 0;
- for (i = 0; i < clients_count; i++) {
- if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
- clients[i] = NULL;
- else
- valid_count++;
- }
-
- if (!valid_count) {
- /* No valid entries found at all, just send error */
- tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
- SILC_STATUS_ERR_NO_SUCH_NICK, 0,
- 3, tmp, tmp ? strlen(tmp) : 0);
- return;
- }
-
- if (valid_count > 1)
- status = SILC_STATUS_LIST_START;
-
- for (i = 0, k = 0; i < clients_count; i++) {
- entry = clients[i];
- if (!entry)
- continue;
-
- if (k >= 1)
- status = SILC_STATUS_LIST_ITEM;
- if (valid_count > 1 && k == valid_count - 1)
- status = SILC_STATUS_LIST_END;
- if (count && k - 1 == count)
- status = SILC_STATUS_LIST_END;
-
- /* Send WHOWAS 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));
-
- 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);
- }
- }
-
- strncat(uh, entry->username, strlen(entry->username));
- if (!strchr(entry->username, '@')) {
- strncat(uh, "@", 1);
- strcat(uh, "*private*");
- }
-
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
- status, 0, ident, 4,
- 2, idp->data, idp->len,
- 3, nh, strlen(nh),
- 4, uh, strlen(uh),
- 5, entry->userinfo,
- entry->userinfo ?
- strlen(entry->userinfo) : 0);
- silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
- 0, packet->data, packet->len, FALSE);
-
- silc_buffer_free(packet);
- silc_buffer_free(idp);
-
- if (status == SILC_STATUS_LIST_END)
- break;
- k++;
- }
-}
-
-static int
-silc_server_command_whowas_process(SilcServerCommandContext cmd)
-{
- SilcServer server = cmd->server;
- char *nick = NULL, *server_name = NULL;
- int count = 0;
- SilcClientEntry *clients = NULL;
- SilcUInt32 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 (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
- server->server_type == SILC_SERVER && !cmd->pending &&
- !server->standalone) {
- SilcBuffer tmpbuf;
- SilcUInt16 old_ident;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, ++server->cmd_ident);
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- /* Send WHOWAS command to our router */
- silc_server_packet_send(server, (SilcSocketConnection)
- server->router->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
-
- /* Reprocess this packet after received reply from router */
- silc_server_command_pending(server, SILC_COMMAND_WHOWAS,
- silc_command_get_ident(cmd->payload),
- silc_server_command_whowas,
- 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. */
-
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
- check_global = TRUE;
- else if (server->server_type != SILC_SERVER)
- check_global = TRUE;
-
- /* Parse the whowas request */
- if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count))
- return 0;
-
- /* Get all clients matching that nickname from local list */
- 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);
-
- /* Check global list as well */
- 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 (!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, 0,
- 3, nick, strlen(nick));
- goto out;
- }
-
- if (!silc_server_command_whowas_check(cmd, clients, clients_count)) {
- ret = -1;
- goto out;
- }
-
- /* Send the command reply to the client */
- silc_server_command_whowas_send_reply(cmd, clients, clients_count);
-
- out:
- silc_free(clients);
- silc_free(nick);
- silc_free(server_name);
- return ret;
-}
-
-/* Server side of command WHOWAS. */
-
-SILC_SERVER_CMD_FUNC(whowas)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- int ret = 0;
-
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOWAS, cmd, 1, 2);
-
- ret = silc_server_command_whowas_process(cmd);
- silc_server_command_free(cmd);
-}
-
-/******************************************************************************
-
- IDENTIFY Functions
-
-******************************************************************************/
-
-static void
-silc_server_command_identify_send_router(SilcServerCommandContext cmd)
-{
- SilcServer server = cmd->server;
- SilcBuffer tmpbuf;
- SilcUInt16 old_ident;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, ++server->cmd_ident);
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- /* Send IDENTIFY command to our router */
- silc_server_packet_send(server, (SilcSocketConnection)
- server->router->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
-
- /* Reprocess this packet after received reply from router */
- silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
- silc_command_get_ident(cmd->payload),
- silc_server_command_identify,
- silc_server_command_dup(cmd));
- cmd->pending = TRUE;
- silc_command_set_ident(cmd->payload, old_ident);
- silc_buffer_free(tmpbuf);
-}
-
-static int
-silc_server_command_identify_parse(SilcServerCommandContext cmd,
- SilcClientEntry **clients,
- SilcUInt32 *clients_count,
- SilcServerEntry **servers,
- SilcUInt32 *servers_count,
- SilcChannelEntry **channels,
- SilcUInt32 *channels_count,
- SilcUInt32 *count,
- ResolveError *error_id,
- SilcUInt32 *error_id_count)
-{
- SilcServer server = cmd->server;
- unsigned char *tmp;
- SilcUInt32 len;
- SilcUInt32 argc = silc_argument_get_arg_num(cmd->args);
- SilcIDPayload idp;
- bool check_global = FALSE;
- void *entry;
- int i;
-
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
- check_global = TRUE;
- else if (server->server_type != SILC_SERVER)
- check_global = TRUE;
-
- /* 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. */
-
- /* If we are normal server and have not resolved information from
- router yet, do so now. */
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
- server->server_type == SILC_SERVER && !cmd->pending &&
- !server->standalone) {
- silc_server_command_identify_send_router(cmd);
- return -1;
- }
-
- /* 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_parse_userfqdn(tmp, &nick, &nick_server);
-
- 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);
- }
-
- silc_free(nick);
- silc_free(nick_server);
-
- if (!(*clients)) {
- /* the nickname does not exist, send error reply */
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_NICK, 0,
- 3, tmp, strlen(tmp));
- return 0;
- }
- }
-
- /* 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->global_list,
- tmp, TRUE, NULL);
- if (entry) {
- *servers = silc_realloc(*servers, sizeof(**servers) *
- (*servers_count + 1));
- (*servers)[(*servers_count)++] = entry;
- }
-
- if (!(*servers)) {
- /* the server does not exist, send error reply */
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_SERVER,
- 0, 3, tmp, strlen(tmp));
- return 0;
- }
- }
-
- /* 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->global_list,
- tmp, NULL);
- if (entry) {
- *channels = silc_realloc(*channels, sizeof(**channels) *
- (*channels_count + 1));
- (*channels)[(*channels_count)++] = entry;
- }
-
- if (!(*channels)) {
- /* The channel does not exist, send error reply */
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL,
- 0, 3, tmp, strlen(tmp));
- return 0;
- }
- }
-
- if (!(*clients) && !(*servers) && !(*channels)) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
- 0);
- return 0;
- }
- } 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(tmp, len);
- if (!idp)
- ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-
- id = silc_id_payload_get_id(idp);
- switch (silc_id_payload_get_type(idp)) {
-
- case SILC_ID_CLIENT:
- 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) {
- *clients = silc_realloc(*clients, sizeof(**clients) *
- (*clients_count + 1));
- (*clients)[(*clients_count)++] = (SilcClientEntry)entry;
- } else {
- /* If we are normal server and have not resolved information from
- router yet, do so now. */
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
- server->server_type == SILC_SERVER && !cmd->pending &&
- !server->standalone) {
- silc_server_command_identify_send_router(cmd);
- silc_free(*clients);
- silc_free(*servers);
- silc_free(*channels);
- silc_free(*error_id);
- return -1;
- }
-
- ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
- }
-
- break;
-
- case SILC_ID_SERVER:
- 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) {
- *servers = silc_realloc(*servers, sizeof(**servers) *
- (*servers_count + 1));
- (*servers)[(*servers_count)++] = (SilcServerEntry)entry;
- } else {
- /* If we are normal server and have not resolved information from
- router yet, do so now. */
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
- server->server_type == SILC_SERVER && !cmd->pending &&
- !server->standalone) {
- silc_server_command_identify_send_router(cmd);
- silc_free(*clients);
- silc_free(*servers);
- silc_free(*channels);
- silc_free(*error_id);
- return -1;
- }
-
- ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
- SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
- }
- break;
-
- case SILC_ID_CHANNEL:
- 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) {
- *channels = silc_realloc(*channels, sizeof(**channels) *
- (*channels_count + 1));
- (*channels)[(*channels_count)++] = (SilcChannelEntry)entry;
- } else {
- /* If we are normal server and have not resolved information from
- router yet, do so now. */
- if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
- server->server_type == SILC_SERVER && !cmd->pending &&
- !server->standalone) {
- silc_server_command_identify_send_router(cmd);
- silc_free(*clients);
- silc_free(*servers);
- silc_free(*channels);
- silc_free(*error_id);
- return -1;
- }
-
- ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
- }
- break;
- }
-
- silc_free(id);
- }
- }
-
- /* Get the max count of reply messages allowed */
- tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
- if (tmp)
- SILC_GET32_MSB(*count, tmp);
- else
- *count = 0;
-
- return 1;
-}
-
-/* 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,
- SilcUInt32 clients_count)
-{
- SilcServer server = cmd->server;
- SilcClientEntry entry;
- SilcServerResolveContext resolve = NULL, r = NULL;
- SilcUInt32 resolve_count = 0;