+ bool error = FALSE;
+
+ 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,
+ 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,
+ 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,
+ 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);
+ 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) {
+ 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 0;
+ }
+
+ 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 {
+ /* 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);
+ return -1;
+ } 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 {
+ /* 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);
+ return -1;
+ } 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 {
+ /* 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);
+ return -1;
+ } 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 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,
+ uint32 clients_count)
+{
+ SilcServer server = cmd->server;