From: Pekka Riikonen Date: Wed, 11 Jul 2001 22:24:29 +0000 (+0000) Subject: updates. X-Git-Tag: robodoc-323~80 X-Git-Url: http://git.silc.fi/gitweb/?p=silc.git;a=commitdiff_plain;h=a13a1924bf35d6f8d9422a2c60364329fd6511b3 updates. --- diff --git a/CHANGES b/CHANGES index f170b1d9..fe7056cd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,44 @@ +Wed Jul 11 18:31:57 EEST 2001 Pekka Riikonen + + * Added SilcClientParams structure to the lib/silcclient/silcapi.h + which is given as argument to the silc_client_alloc now. + It can be used to configure the client and set various parameters + that affect the function of the client. + + * The USERS command in server did not check whether the channel + is private or secret. Affected file silcd/command.c. + + * Added new argument to the USERS command in protocol specification. + The USERS command now can take the channel name as argument + as well. Added support for this in client and server and + updated the protocol specs. + + * Completed the GETKEY command in client. It can be now used + to fetch also servers public key not only some clients. + Affected files lib/silcclient/command[_reply].c. + + * Added silc_client_get_server to return server entry by the + server name. Affected files lib/silcclient/silcapi.h and + idlist.c. + + * Redefined the IDENTIFY command in protocol specification to be + more generic. It now can be used to query information about + any entity in the SILC Network, including clients, servers and + channels. The query may be based either the entity's name + or the ID. Added support for this in both client and server. + + Affected files silcd/command.c and lib/silcclient/command.c + and command_reply.c. + + * Optimized the WHOIS and WHOWAS commands in the server. Removed + the _from_client and _from_server functions. Affected file + silcd/command.c. + + * Added silc_client_get_channel_by_id_resolve to the file + lib/silcclient/silcapi.h to resolve channel information by + its ID. Added also silc_client_get_channel_by_id that + does not resolve it from the server. + Tue Jul 10 18:05:38 EEST 2001 Pekka Riikonen * Added SilcServerEntry context into the client library diff --git a/TODO b/TODO index b6c1447d..4f205059 100644 --- a/TODO +++ b/TODO @@ -22,10 +22,8 @@ TODO/bugs in Irssi SILC client TODO/bugs In SILC Client Library ================================ - o All protocol execution timeouts are hard coded. They should be - configurable and the Irssi SILC client should be able to set them - with for example /set key_exchange_timeout etc. The silc_client_alloc - should take a Params structure or something as argument. + o The public key authentication is missing for example in OPER and SILCOPER + commands. See the XXX's in the lib/silcclient/command.c. o The client library must manage somehow when receiving client that has same nickname, same server, same username but different Client ID than diff --git a/apps/irssi/docs/help/in/getkey.in b/apps/irssi/docs/help/in/getkey.in index d2c5ee0a..38b63b49 100644 --- a/apps/irssi/docs/help/in/getkey.in +++ b/apps/irssi/docs/help/in/getkey.in @@ -1,10 +1,9 @@ @SYNTAX:getkey@ -This command is used to fetch remote client's public key. -The public key is fetched from the server the client is -connected to. This way the public key might have been -verified already. However, you will be prompted to verify +This command is used to fetch remote client's or server's public +key. When fetching client's public key it is fetched from the +server the client is connected to. This way the public key might +have been verified already. However, you will be prompted to verify the fetched public key. The public key is saved into your local key directory (~/.silc/clientkeys/). - diff --git a/apps/irssi/src/silc/core/client_ops.c b/apps/irssi/src/silc/core/client_ops.c index b873e2cb..e41cd55a 100644 --- a/apps/irssi/src/silc/core/client_ops.c +++ b/apps/irssi/src/silc/core/client_ops.c @@ -676,10 +676,12 @@ silc_command_reply(SilcClient client, SilcClientConnection conn, pk = silc_pkcs_public_key_encode(public_key, &pk_len); - if (id_type == SILC_ID_CLIENT) - silc_verify_public_key_internal(client, conn, SILC_SOCKET_TYPE_CLIENT, - pk, pk_len, SILC_SKE_PK_TYPE_SILC, - NULL, NULL); + silc_verify_public_key_internal(client, conn, + (id_type == SILC_ID_CLIENT ? + SILC_SOCKET_TYPE_CLIENT : + SILC_SOCKET_TYPE_SERVER), + pk, pk_len, SILC_SKE_PK_TYPE_SILC, + NULL, NULL); silc_free(pk); } break; diff --git a/apps/irssi/src/silc/core/silc-core.c b/apps/irssi/src/silc/core/silc-core.c index d29ad5ee..da42b3b3 100644 --- a/apps/irssi/src/silc/core/silc-core.c +++ b/apps/irssi/src/silc/core/silc-core.c @@ -271,7 +271,7 @@ void silc_core_init_finish(void) silc_init_userinfo(); /* Allocate SILC client */ - silc_client = silc_client_alloc(&ops, NULL, silc_version_string); + silc_client = silc_client_alloc(&ops, NULL, NULL, silc_version_string); /* Load local config file */ silc_config = silc_client_config_alloc(SILC_CLIENT_HOME_CONFIG_FILE); diff --git a/apps/irssi/src/silc/core/silc-servers.c b/apps/irssi/src/silc/core/silc-servers.c index 566b269a..574979c7 100644 --- a/apps/irssi/src/silc/core/silc-servers.c +++ b/apps/irssi/src/silc/core/silc-servers.c @@ -253,7 +253,7 @@ char *silc_server_get_channels(SILC_SERVER_REC *server) /* SYNTAX: BAN [+|-[[@[![@hostname>]]]]] */ /* SYNTAX: CMODE +|- [{ }] */ /* SYNTAX: CUMODE +|- [@] [-pubkey|] */ -/* SYNTAX: GETKEY */ +/* SYNTAX: GETKEY */ /* SYNTAX: INVITE [[@server>] */ /* SYNTAX: INVITE [+|-[[@[![@hostname>]]]]] */ /* SYNTAX: KEY MSG set|unset|list|agreement|negotiate [] */ diff --git a/apps/silc/Makefile.am b/apps/silc/Makefile.am index e216b583..ced6a4b1 100644 --- a/apps/silc/Makefile.am +++ b/apps/silc/Makefile.am @@ -18,17 +18,15 @@ AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign -bin_PROGRAMS = silc - -silc_SOURCES = \ - silc.c \ - clientconfig.c \ - clientutil.c \ - local_command.c \ - screen.c \ - client_ops.c - -silc_DEPENDENCIES = ../lib/libsilcclient.a ../lib/libsilc.a +#bin_PROGRAMS = silc +#silc_SOURCES = \ +# silc.c \ +# clientconfig.c \ +# clientutil.c \ +# local_command.c \ +# screen.c \ +# client_ops.c +#silc_DEPENDENCIES = ../lib/libsilcclient.a ../lib/libsilc.a LIBS = $(SILC_COMMON_LIBS) LDADD = -L. -L.. -L../lib -lsilcclient diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 52a4a78f..bdb236d3 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -422,7 +422,10 @@ silc_server_command_pending_error_check(SilcServerCommandContext cmd, return FALSE; SILC_GET16_MSB(status, silc_argument_get_arg_type(cmdr->args, 1, NULL)); - if (status != SILC_STATUS_OK) { + 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; @@ -503,8 +506,6 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd, } } } - - /* Command includes ID, use that */ } /* Get the max count of reply messages allowed */ @@ -703,7 +704,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd, } 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; @@ -712,12 +713,14 @@ silc_server_command_whois_from_client(SilcServerCommandContext cmd) 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; @@ -750,110 +753,10 @@ silc_server_command_whois_from_client(SilcServerCommandContext cmd) /* 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, @@ -861,14 +764,15 @@ silc_server_command_whois_from_server(SilcServerCommandContext cmd) 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); + if (!entry && check_global) + 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)); @@ -882,22 +786,7 @@ silc_server_command_whois_from_server(SilcServerCommandContext cmd) 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)) @@ -906,9 +795,9 @@ silc_server_command_whois_from_server(SilcServerCommandContext cmd) &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, @@ -933,7 +822,7 @@ silc_server_command_whois_from_server(SilcServerCommandContext cmd) goto out; } - /* Send the command reply to the client */ + /* Send the command reply */ silc_server_command_whois_send_reply(cmd, clients, clients_count, count); @@ -963,11 +852,7 @@ SILC_SERVER_CMD_FUNC(whois) 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); @@ -1165,7 +1050,7 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd, } 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; @@ -1173,12 +1058,14 @@ silc_server_command_whowas_from_client(SilcServerCommandContext cmd) 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 && + if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && + server->server_type == SILC_SERVER && !cmd->pending && !server->standalone) { SilcBuffer tmpbuf; uint16 old_ident; @@ -1211,6 +1098,11 @@ silc_server_command_whowas_from_client(SilcServerCommandContext cmd) /* 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; @@ -1224,66 +1116,7 @@ silc_server_command_whowas_from_client(SilcServerCommandContext cmd) &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 (!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 (!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: - if (clients) - silc_free(clients); - if (nick) - silc_free(nick); - if (server_name) - silc_free(server_name); - - return ret; -} - -static int -silc_server_command_whowas_from_server(SilcServerCommandContext cmd) -{ - SilcServer server = cmd->server; - char *nick = NULL, *server_name = NULL; - int count = 0; - SilcClientEntry *clients = NULL; - uint32 clients_count = 0; - int ret = 0; - - /* Parse the whowas request */ - if (!silc_server_command_whowas_parse(cmd, &nick, &server_name, &count)) - return 0; - - /* Process the command request. Let's search for the requested client and - send reply to the requesting server. */ - - 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 (check_global) { if (!silc_idlist_get_clients_by_nickname(server->global_list, nick, server_name, &clients, &clients_count)) @@ -1291,7 +1124,7 @@ silc_server_command_whowas_from_server(SilcServerCommandContext cmd) 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, @@ -1300,6 +1133,12 @@ silc_server_command_whowas_from_server(SilcServerCommandContext cmd) goto out; } + if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && + !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); @@ -1323,11 +1162,7 @@ SILC_SERVER_CMD_FUNC(whowas) SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WHOWAS, cmd, 1, 2); - 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); + ret = silc_server_command_whowas_process(cmd); if (!ret) silc_server_command_free(cmd); @@ -1339,14 +1174,238 @@ SILC_SERVER_CMD_FUNC(whowas) ******************************************************************************/ -/* 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. */ +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; + + if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) + check_global = TRUE; + else if (server->server_type == SILC_ROUTER) + 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. */ + + /* Try to get nickname@server. */ + tmp = silc_argument_get_arg_type(cmd->args, 1, NULL); + if (tmp) { + char *nick = NULL; + char *nick_server = NULL; + + if (strchr(tmp, '@')) { + len = strcspn(tmp, "@"); + nick = silc_calloc(len + 1, sizeof(char)); + memcpy(nick, tmp, len); + nick_server = silc_calloc(strlen(tmp) - len, sizeof(char)); + memcpy(nick_server, tmp + len + 1, strlen(tmp) - len - 1); + } else { + nick = strdup(tmp); + } + + 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)) { + silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY, + SILC_STATUS_ERR_NO_SUCH_NICK, + 3, tmp, strlen(tmp)); + return FALSE; + } + } + + /* 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, NULL); + if (!entry && check_global) + entry = silc_idlist_find_server_by_name(server->local_list, + tmp, 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; + } + } + + /* 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; + } + + 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, NULL); + if (!entry && check_global) + entry = (void *)silc_idlist_find_client_by_id(server->global_list, + id, 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, NULL); + if (!entry && check_global) + entry = (void *)silc_idlist_find_server_by_id(server->global_list, + id, 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 char -silc_server_command_identify_check(SilcServerCommandContext cmd, - SilcClientEntry *clients, - uint32 clients_count) +silc_server_command_identify_check_client(SilcServerCommandContext cmd, + SilcClientEntry *clients, + uint32 clients_count) { SilcServer server = cmd->server; int i; @@ -1401,121 +1460,218 @@ 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 (clients) { + SilcClientEntry entry; + + len = 0; + for (i = 0; i < clients_count; i++) + if (clients[i]->data.registered) + len++; + + 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 (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 (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; + + /* Send IDENTIFY reply */ + idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT); + + 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); + } + } + + 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)); + } + + 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++; + } + } + + status = (status == SILC_STATUS_LIST_ITEM ? + SILC_STATUS_LIST_ITEM : SILC_STATUS_OK); - status = SILC_STATUS_OK; - if (len > 1) - status = SILC_STATUS_LIST_START; + if (servers) { + SilcServerEntry entry; - for (i = 0, k = 0; i < clients_count; i++) { - entry = clients[i]; + if (status == SILC_STATUS_OK && servers_count > 1) + status = SILC_STATUS_LIST_START; - if (entry->data.registered == FALSE) { - 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); + 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); } - continue; + + 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 (k >= 1) - status = SILC_STATUS_LIST_ITEM; - - if (clients_count > 1 && k == clients_count - 1) - status = SILC_STATUS_LIST_END; + status = (status == SILC_STATUS_LIST_ITEM ? + SILC_STATUS_LIST_ITEM : SILC_STATUS_OK); - if (count && k - 1 == count) - status = SILC_STATUS_LIST_END; + if (channels) { + SilcChannelEntry entry; - if (count && k - 1 > count) - break; + if (status == SILC_STATUS_OK && channels_count > 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 < channels_count; i++) { + entry = channels[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)); + 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 { - len = entry->router ? strlen(entry->router->server_name) : - strlen(server->server_name); - strncat(nh, entry->router ? entry->router->server_name : - server->server_name, len); + packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY, + status, ident, 1, + 2, idp->data, idp->len); } - } - 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); - } + silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, + 0, packet->data, packet->len, FALSE); - 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)); - } + silc_buffer_free(packet); + silc_buffer_free(idp); - 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++; + k++; + } } } static int -silc_server_command_identify_from_client(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; /* 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) { + if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && + server->server_type == SILC_SERVER && !cmd->pending && + !server->standalone) { SilcBuffer tmpbuf; uint16 old_ident; @@ -1548,197 +1704,32 @@ silc_server_command_identify_from_client(SilcServerCommandContext cmd) 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)) + if (!silc_server_command_identify_parse(cmd, + &clients, &clients_count, + &servers, &servers_count, + &channels, &channels_count, + &count)) 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 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); - } - 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)) { + if (clients && !silc_server_command_identify_check_client(cmd, clients, + clients_count)) { ret = -1; goto out; } /* Send the command reply to the client */ - silc_server_command_identify_send_reply(cmd, clients, clients_count, + 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); - - return ret; -} - -static int -silc_server_command_identify_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; - - /* 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; - - /* Process the command request. Let's search for the requested client and - send reply to the requesting server. */ - - 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); - } - } - - 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); - } - 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; - } - - /* Send the command reply */ - silc_server_command_identify_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); + silc_free(clients); + silc_free(servers); + silc_free(channels); return ret; } @@ -1750,11 +1741,7 @@ SILC_SERVER_CMD_FUNC(identify) 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); @@ -4741,8 +4728,8 @@ SILC_SERVER_CMD_FUNC(users) 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; @@ -4750,27 +4737,40 @@ SILC_SERVER_CMD_FUNC(users) unsigned char lc[4]; uint32 list_count = 0; uint16 ident = silc_command_get_ident(cmd->payload); + char *channel_name; - SILC_SERVER_COMMAND_CHECK(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) { @@ -4799,7 +4799,11 @@ SILC_SERVER_CMD_FUNC(users) } /* We are router and we will check the global list as well. */ - channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL); + if (id) + channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL); + else + channel = silc_idlist_find_channel_by_name(server->local_list, + channel_name, NULL); if (!channel) { /* Channel really does not exist */ silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS, @@ -4808,6 +4812,13 @@ SILC_SERVER_CMD_FUNC(users) } } + /* If the channel is private or secret do not send anything */ + 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); @@ -4816,9 +4827,10 @@ SILC_SERVER_CMD_FUNC(users) 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, @@ -4827,10 +4839,12 @@ SILC_SERVER_CMD_FUNC(users) 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); diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index a012aa8c..557a857f 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -404,94 +404,182 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) SilcServer server = cmd->server; uint32 len, id_len; unsigned char *id_data; - char *nickname, *username; - SilcClientID *client_id; + char *name, *info; + SilcClientID *client_id = NULL; + SilcServerID *server_id = NULL; + SilcChannelID *channel_id = NULL; SilcClientEntry client; + SilcServerEntry server_entry; + SilcChannelEntry channel; char global = FALSE; char *nick = NULL; + SilcIDPayload idp = NULL; + SilcIdType id_type; id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len); - nickname = silc_argument_get_arg_type(cmd->args, 3, &len); - username = silc_argument_get_arg_type(cmd->args, 4, &len); if (!id_data) return FALSE; - - client_id = silc_id_payload_parse_id(id_data, id_len); - if (!client_id) + idp = silc_id_payload_parse_data(id_data, id_len); + if (!idp) return FALSE; - /* Check if we have this client cached already. */ + name = silc_argument_get_arg_type(cmd->args, 3, &len); + info = silc_argument_get_arg_type(cmd->args, 4, &len); - client = silc_idlist_find_client_by_id(server->local_list, client_id, NULL); - if (!client) { - client = silc_idlist_find_client_by_id(server->global_list, client_id, - NULL); - global = TRUE; - } + id_type = silc_id_payload_get_type(idp); - if (!client) { - /* If router did not find such Client ID in its lists then this must - be bogus client or some router in the net is buggy. */ - if (server->server_type == SILC_ROUTER) - return FALSE; + switch (id_type) { + case SILC_ID_CLIENT: + client_id = silc_id_payload_get_id(idp); + if (!client_id) + goto error; - /* Take hostname out of nick string if it includes it. */ - if (nickname) { - if (strchr(nickname, '@')) { - int len = strcspn(nickname, "@"); - nick = silc_calloc(len + 1, sizeof(char)); - memcpy(nick, nickname, len); - } else { - nick = strdup(nickname); + SILC_LOG_DEBUG(("Received client information")); + + client = silc_idlist_find_client_by_id(server->local_list, + client_id, NULL); + if (!client) { + client = silc_idlist_find_client_by_id(server->global_list, client_id, + NULL); + global = TRUE; + } + if (!client) { + /* If router did not find such Client ID in its lists then this must + be bogus client or some router in the net is buggy. */ + if (server->server_type == SILC_ROUTER) + goto error; + + /* Take hostname out of nick string if it includes it. */ + if (name) { + if (strchr(name, '@')) { + int len = strcspn(name, "@"); + nick = silc_calloc(len + 1, sizeof(char)); + memcpy(nick, name, len); + } else { + nick = strdup(name); + } } + + /* We don't have that client anywhere, add it. The client is added + to global list since server didn't have it in the lists so it must be + global. */ + client = silc_idlist_add_client(server->global_list, nick, + info ? strdup(info) : NULL, NULL, + client_id, cmd->sock->user_data, NULL); + client->data.registered = TRUE; + } else { + /* We have the client already, update the data */ + + SILC_LOG_DEBUG(("Updating client data")); + + /* Take hostname out of nick string if it includes it. */ + if (name) { + if (strchr(name, '@')) { + int len = strcspn(name, "@"); + nick = silc_calloc(len + 1, sizeof(char)); + memcpy(nick, name, len); + } else { + nick = strdup(name); + } + } + + if (name && client->nickname) + silc_free(client->nickname); + + if (nick) + client->nickname = nick; + + if (info && client->username) { + silc_free(client->username); + client->username = strdup(info); + } + + /* Remove the old cache entry and create a new one */ + if (name) { + silc_idcache_del_by_context(global ? server->global_list->clients : + server->local_list->clients, client); + silc_idcache_add(global ? server->global_list->clients : + server->local_list->clients, nick, client->id, + client, FALSE); + } + + silc_free(client_id); } - /* We don't have that client anywhere, add it. The client is added - to global list since server didn't have it in the lists so it must be - global. */ - client = silc_idlist_add_client(server->global_list, nick, - username ? strdup(username) : NULL, NULL, - client_id, cmd->sock->user_data, NULL); - client->data.registered = TRUE; - } else { - /* We have the client already, update the data */ + break; - SILC_LOG_DEBUG(("Updating client data")); + case SILC_ID_SERVER: + server_id = silc_id_payload_get_id(idp); + if (!server_id) + goto error; - /* Take hostname out of nick string if it includes it. */ - if (nickname) { - if (strchr(nickname, '@')) { - int len = strcspn(nickname, "@"); - nick = silc_calloc(len + 1, sizeof(char)); - memcpy(nick, nickname, len); - } else { - nick = strdup(nickname); + SILC_LOG_DEBUG(("Received server information")); + + server_entry = silc_idlist_find_server_by_id(server->local_list, + server_id, NULL); + if (!server_entry) + server_entry = silc_idlist_find_server_by_id(server->global_list, + server_id, NULL); + if (!server_entry) { + /* If router did not find such Server ID in its lists then this must + be bogus client or some router in the net is buggy. */ + if (server->server_type == SILC_ROUTER) + goto error; + + /* We don't have that server anywhere, add it. */ + server_entry = silc_idlist_add_server(server->global_list, + strdup(name), 0, + server_id, NULL, NULL); + if (!server_entry) { + silc_free(server_id); + goto error; } + server_id = NULL; } - if (nickname && client->nickname) - silc_free(client->nickname); + silc_free(server_id); + break; - if (nickname) - client->nickname = nick; + case SILC_ID_CHANNEL: + channel_id = silc_id_payload_get_id(idp); + if (!channel_id) + goto error; - if (username && client->username) { - silc_free(client->username); - client->username = strdup(username); - } + SILC_LOG_DEBUG(("Received channel information")); - /* Remove the old cache entry and create a new one */ - if (nickname) { - silc_idcache_del_by_context(global ? server->global_list->clients : - server->local_list->clients, client); - silc_idcache_add(global ? server->global_list->clients : - server->local_list->clients, nick, client->id, - client, FALSE); + channel = silc_idlist_find_channel_by_id(server->local_list, + channel_id, NULL); + if (!channel) + channel = silc_idlist_find_channel_by_id(server->global_list, channel_id, + NULL); + if (!channel) { + /* If router did not find such Server ID in its lists then this must + be bogus client or some router in the net is buggy. */ + if (server->server_type == SILC_ROUTER) + goto error; + + /* We don't have that server anywhere, add it. */ + channel = silc_idlist_add_channel(server->global_list, strdup(name), + SILC_CHANNEL_MODE_NONE, channel_id, + server->router->connection, + NULL, NULL); + if (!channel) { + silc_free(channel_id); + goto error; + } + channel_id = NULL; } - silc_free(client_id); + + silc_free(channel_id); + break; } + silc_id_payload_free(idp); return TRUE; + + error: + silc_id_payload_free(idp); + return FALSE; } /* Received reply for forwarded IDENTIFY command. We have received the @@ -855,8 +943,26 @@ SILC_SERVER_CMD_REPLY_FUNC(users) if (!channel) { channel = silc_idlist_find_channel_by_id(server->global_list, channel_id, NULL); - if (!channel) - goto out; + if (!channel) { + SilcBuffer idp; + + if (server->server_type == SILC_ROUTER) + goto out; + + idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL); + silc_server_send_command(server, server->router->connection, + SILC_COMMAND_IDENTIFY, ++server->cmd_ident, + 1, 5, idp->data, idp->len); + silc_buffer_free(idp); + + /* Register pending command callback. After we've received the channel + information we will reprocess this command reply by re-calling this + USERS command reply callback. */ + silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, + server->cmd_ident, + NULL, silc_server_command_reply_users, cmd); + return; + } } /* Get the list count */ diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index 4e5f5272..0d7ed54d 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -558,6 +558,8 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode, { SilcChannelEntry channel; + SILC_LOG_DEBUG(("Adding new channel entry")); + channel = silc_calloc(1, sizeof(*channel)); channel->channel_name = channel_name; channel->mode = mode; diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 7ac6826f..be1ee659 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -1864,7 +1864,7 @@ void silc_server_new_channel(SilcServer server, id = silc_channel_get_id(payload, &id_len); if (sock->type == SILC_SOCKET_TYPE_ROUTER) { - /* Add the server to global list as it is coming from router. It + /* Add the channel to global list as it is coming from router. It cannot be our own channel as it is coming from router. */ SILC_LOG_DEBUG(("New channel id(%s) from [Router] %s", diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index c550fbae..31e9bea1 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -1573,6 +1573,7 @@ void silc_server_send_channel_key(SilcServer server, void silc_server_send_command(SilcServer server, SilcSocketConnection sock, SilcCommand command, + uint16 ident, uint32 argc, ...) { SilcBuffer packet; @@ -1580,7 +1581,7 @@ void silc_server_send_command(SilcServer server, va_start(ap, argc); - packet = silc_command_payload_encode_vap(command, 0, argc, ap); + packet = silc_command_payload_encode_vap(command, ident, argc, ap); silc_server_packet_send(server, sock, SILC_PACKET_COMMAND, 0, packet->data, packet->len, TRUE); silc_buffer_free(packet); diff --git a/apps/silcd/packet_send.h b/apps/silcd/packet_send.h index 5a185233..67f54c0d 100644 --- a/apps/silcd/packet_send.h +++ b/apps/silcd/packet_send.h @@ -213,6 +213,7 @@ void silc_server_send_channel_key(SilcServer server, void silc_server_send_command(SilcServer server, SilcSocketConnection sock, SilcCommand command, + uint16 ident, uint32 argc, ...); void silc_server_send_heartbeat(SilcServer server, SilcSocketConnection sock); diff --git a/doc/draft-riikonen-silc-commands-01.nroff b/doc/draft-riikonen-silc-commands-01.nroff index c03fd192..1b538c85 100644 --- a/doc/draft-riikonen-silc-commands-01.nroff +++ b/doc/draft-riikonen-silc-commands-01.nroff @@ -234,15 +234,15 @@ List of all defined commands in SILC follows. nicknames in the SILC. The option may be given to narrow down the number of accepted results. If this is not defined there are no limit of accepted results. The query may also be narrowed - down by defining the server name of the nickname. + down by defining the server name of the nickname. The is + int string format. It is also possible to search the user by Client ID. If the is provided server MUST use it as the search value instead of the . One of the arguments MUST be given. It is also possible to define multiple Client ID's to search multiple users sending only one WHOIS command. In this case the - Client ID's are appended as normal arguments. The server replies - in this case with only one reply message for all requested users. + Client ID's are appended as normal arguments. To prevent miss-use of this command wildcards in the nickname or in the server name are not permitted. It is not allowed @@ -311,7 +311,7 @@ List of all defined commands in SILC follows. given to narrow down the number of accepted results. If this is not defined there are no limit of accepted results. The query may also be narrowed down by defining the server name of the - nickname. + nickname. The is in string format. To prevent miss-use of this command wildcards in the nickname or in the server name are not permitted. The WHOWAS requests MUST @@ -352,49 +352,45 @@ List of all defined commands in SILC follows. 3 SILC_COMMAND_IDENTIFY Max Arguments: 3328 - Arguments: (1) [[@]] (2) [] - (3) [] (n) [...] - - Identify. Identify command is almost analogous to WHOIS command, - except that it does not return as much information. Only relevant - information such as Client ID is returned. This is usually used - to get the Client ID of a client used in the communication with - the client. - - The query may find multiple matching users as there are no unique - nicknames in the SILC. The option may be given to narrow - down the number of accepted results. If this is not defined there - are no limit of accepted results. The query may also be narrowed - down by defining the server name of the nickname. - - It is also possible to search the user by Client ID. If the - is provided server must use it as the search value - instead of the . One of the arguments must be given. - It is also possible to define multiple Client ID's to search - multiple users sending only one IDENTIFY command. In this case - the Client ID's are appended as normal arguments. The server - replies in this case with only one reply message for all requested - users. - - To prevent miss-use of this command wildcards in the nickname - or in the server name are not permitted. It is not allowed - to request all users on some server. The IDENTIFY requests MUST - be based on specific nickname request. + Arguments: (1) [[@]] (2) [] + (3) [] (4) [] + (5) [] (n) [...] + + Identify command is used to query information about an entity by + the entity's name or ID. This command can be used to query + information about clients, server and channels. + + The query may find multiple matching entities. The option + may be given to narrow down the number of accepted results. If + this is not defined there are no limit of accepted results. The + is in string format. + + It is also possible to search the entity by its ID. If the + is provided server must use it as the search value + instead of the entity's name. One of the arguments must be given. + It is also possible to define multiple ID Payloads to search + multiple entities sending only one IDENTIFY command. In this case + the ID Payloads are appended as normal arguments. The type of the + entity is defined by the type of the ID Payload. + + To prevent miss-use of this command wildcards in the names are + not permitted. It is not allowed to request for example all users + on server. Implementations may not want to give interface access to this - command as it is hardly a command that would be used by an end user. - However, it must be implemented as it is used with private message - sending. + command as it is hardly a command that would be used by an end + user. However, it must be implemented as it is used with private + message sending. - The IDENTIFY MUST be always sent to the router by server so that - all users are searched. However, server MUST still search its - locally connected clients. + The IDENTIFY command MUST be always sent to the router by server + so that all users are searched. However, server MUST still search + its locally connected clients. Reply messages to the command: Max Arguments: 4 - Arguments: (1) (2) - (3) [[@]] (4) [] + Arguments: (1) (2) + (3) [] (4) [] This command may reply with several command reply messages to form a list of results. In this case the status payload will include @@ -402,10 +398,19 @@ List of all defined commands in SILC follows. the last reply to indicate the end of the list. If there are only one reply the status is set to normal STATUS_OK. - The command replies with Client ID of the nickname and if more - information is available it MAY reply with nickname and user name - and host name. If the option were defined in the query - there will be only many replies from the server. + When querying clients the must include the client's + nickname in the following format: nickname>[@server]. The + must include the client's username and host in the following + format: username@host. + + When querying servers the must include the server's + full name. The may be omitted. + + When querying channels the must include the + channel's name. The may be omitted. + + If the option were defined in the query there will be only + many replies from the server. Status messages: @@ -413,7 +418,11 @@ List of all defined commands in SILC follows. SILC_STATUS_LIST_START SILC_STATUS_LIST_END SILC_STATUS_ERR_NO_SUCH_NICK + SILC_STATUS_ERR_NO_SUCH_SERVER + SILC_STATUS_ERR_NO_SUCH_CHANNEL SILC_STATUS_ERR_NO_SUCH_CLIENT_ID + SILC_STATUS_ERR_NO_SUCH_SERVER_ID + SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID SILC_STATUS_ERR_WILDCARDS SILC_STATUS_ERR_NOT_ENOUGH_PARAMS SILC_STATUS_ERR_TOO_MANY_PARAMS @@ -667,7 +676,8 @@ List of all defined commands in SILC follows. the requested server. If the is specified the server information if fetched - by the provided Server ID. + by the provided Server ID. One of the arguments must always be + present. Reply messages to the command: @@ -1464,12 +1474,13 @@ List of all defined commands in SILC follows. 25 SILC_COMMAND_USERS - Max Arguments: 1 - Arguments: (1) + Max Arguments: 2 + Arguments: (1) [] (2) [] This command is used to list user names currently on the requested - channel; argument . The server MUST resolve the - user names and send a comma (`,') separated list of user names + channel; either the argument or the . + One of these arguments must be present. The server MUST resolve + the user names and send a comma (`,') separated list of user names on the channel. Server or router MAY resolve the names by sending SILC_COMMAND_WHOIS or SILC_COMMAND_IDENTIFY commands. diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 2f857a1f..b9690500 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -40,7 +40,9 @@ static void silc_client_packet_parse_type(SilcClient client, the client. The `application' is application specific user data pointer and caller must free it. */ -SilcClient silc_client_alloc(SilcClientOperations *ops, void *application, +SilcClient silc_client_alloc(SilcClientOperations *ops, + SilcClientParams *params, + void *application, const char *silc_version) { SilcClient new_client; @@ -49,6 +51,13 @@ SilcClient silc_client_alloc(SilcClientOperations *ops, void *application, new_client->application = application; new_client->ops = ops; new_client->silc_client_version = strdup(silc_version); + new_client->params = silc_calloc(1, sizeof(*new_client->params)); + + if (params) + memcpy(new_client->params, params, sizeof(*params)); + + if (!new_client->params->rekey_secs) + new_client->params->rekey_secs = 3600; return new_client; } @@ -61,6 +70,8 @@ void silc_client_free(SilcClient client) if (client->rng) silc_rng_free(client->rng); + silc_free(client->silc_client_version); + silc_free(client->params); silc_free(client); } } @@ -556,7 +567,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final) conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER); /* Register re-key timeout */ - conn->rekey->timeout = 3600; /* XXX hardcoded */ + conn->rekey->timeout = client->params->rekey_secs; conn->rekey->context = (void *)client; silc_task_register(client->timeout_queue, conn->sock->sock, silc_client_rekey_callback, @@ -1315,7 +1326,8 @@ void silc_client_receive_new_id(SilcClient client, /* Processed received Channel ID for a channel. This is called when client joins to channel and server replies with channel ID. The ID is cached. - Returns the created channel entry. */ + Returns the created channel entry. This is also called when received + channel ID in for example USERS command reply that we do not have. */ SilcChannelEntry silc_client_new_channel_id(SilcClient client, SilcSocketConnection sock, @@ -1334,8 +1346,6 @@ SilcChannelEntry silc_client_new_channel_id(SilcClient client, channel->mode = mode; silc_list_init(channel->clients, struct SilcChannelUserStruct, next); - conn->current_channel = channel; - /* Put it to the ID cache */ silc_idcache_add(conn->channel_cache, channel_name, (void *)channel->id, (void *)channel, FALSE); diff --git a/lib/silcclient/client.h b/lib/silcclient/client.h index 1a3b8565..f886e3d3 100644 --- a/lib/silcclient/client.h +++ b/lib/silcclient/client.h @@ -158,6 +158,9 @@ struct SilcClientStruct { /* All client operations that are implemented in the application. */ SilcClientOperations *ops; + /* Client Parameters */ + SilcClientParams *params; + /* SILC client scheduler and task queues */ SilcSchedule schedule; SilcTaskQueue io_queue; diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index 3e6839fa..cb951937 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -336,17 +336,23 @@ SILC_CLIENT_CMD_FUNC(identify) goto out; } - buffer = silc_command_payload_encode(SILC_COMMAND_IDENTIFY, - cmd->argc - 1, ++cmd->argv, - ++cmd->argv_lens, ++cmd->argv_types, - ++conn->cmd_ident); + if (cmd->argc == 2) + buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY, + ++conn->cmd_ident, 1, + 1, cmd->argv[1], + cmd->argv_lens[1]); + else + buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY, + ++conn->cmd_ident, 2, + 1, cmd->argv[1], + cmd->argv_lens[1], + 4, cmd->argv[2], + cmd->argv_lens[2]); + silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND, NULL, 0, NULL, NULL, buffer->data, buffer->len, TRUE); silc_buffer_free(buffer); - cmd->argv--; - cmd->argv_lens--; - cmd->argv_types--; /* Notify application */ COMMAND; @@ -371,7 +377,8 @@ SILC_CLIENT_CMD_FUNC(nick) } if (cmd->argc < 2) { - cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /NICK "); + cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + "Usage: /NICK "); COMMAND_ERROR; goto out; } @@ -1975,14 +1982,16 @@ SILC_CLIENT_CMD_FUNC(leave) } if (cmd->argc != 2) { - cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /LEAVE "); + cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + "Usage: /LEAVE "); COMMAND_ERROR; goto out; } if (cmd->argv[1][0] == '*') { if (!conn->current_channel) { - cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel"); + cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + "You are not on any channel"); COMMAND_ERROR; goto out; } @@ -1993,7 +2002,8 @@ SILC_CLIENT_CMD_FUNC(leave) /* Get the Channel ID of the channel */ if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) { - cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel"); + cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + "You are not on that channel"); COMMAND_ERROR; goto out; } @@ -2033,9 +2043,7 @@ SILC_CLIENT_CMD_FUNC(users) { SilcClientCommandContext cmd = (SilcClientCommandContext)context; SilcClientConnection conn = cmd->conn; - SilcIDCacheEntry id_cache = NULL; - SilcChannelEntry channel; - SilcBuffer buffer, idp; + SilcBuffer buffer; char *name; if (!cmd->conn) { @@ -2045,14 +2053,16 @@ SILC_CLIENT_CMD_FUNC(users) } if (cmd->argc != 2) { - cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /USERS "); + cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + "Usage: /USERS "); COMMAND_ERROR; goto out; } if (cmd->argv[1][0] == '*') { if (!conn->current_channel) { - cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on any channel"); + cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, + "You are not on any channel"); COMMAND_ERROR; goto out; } @@ -2061,45 +2071,14 @@ SILC_CLIENT_CMD_FUNC(users) name = cmd->argv[1]; } - if (!conn->current_channel) { - cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "You are not on that channel"); - COMMAND_ERROR; - goto out; - } - - /* Get the Channel ID of the channel */ - if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) { - /* XXX should resolve the channel ID; LIST command */ - cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, - "You are not on that channel", name); - COMMAND_ERROR; - goto out; - } - - channel = (SilcChannelEntry)id_cache->context; - - if (!cmd->pending) { - /* Send USERS command to the server */ - idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL); - buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, - ++conn->cmd_ident, 1, - 1, idp->data, idp->len); - silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, - NULL, 0, NULL, NULL, buffer->data, - buffer->len, TRUE); - silc_buffer_free(buffer); - silc_buffer_free(idp); - - /* Register pending callback which will recall this command callback with - same context and reprocesses the command. When reprocessing we actually - display the information on the screen. */ - silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident, - silc_client_command_destructor, - silc_client_command_users, - silc_client_command_dup(cmd)); - cmd->pending = TRUE; - return; - } + /* Send USERS command to the server */ + buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, + ++conn->cmd_ident, 1, + 2, name, strlen(name)); + silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, + NULL, 0, NULL, NULL, buffer->data, + buffer->len, TRUE); + silc_buffer_free(buffer); /* Notify application */ COMMAND; @@ -2116,6 +2095,7 @@ SILC_CLIENT_CMD_FUNC(getkey) SilcClientConnection conn = cmd->conn; SilcClient client = cmd->client; SilcClientEntry client_entry = NULL; + SilcServerEntry server_entry = NULL; uint32 num = 0; char *nickname = NULL, *server = NULL; SilcBuffer idp, buffer; @@ -2127,7 +2107,8 @@ SILC_CLIENT_CMD_FUNC(getkey) } if (cmd->argc < 2) { - client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, "Usage: /GETKEY "); + client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, + "Usage: /GETKEY "); COMMAND_ERROR; goto out; } @@ -2141,20 +2122,43 @@ SILC_CLIENT_CMD_FUNC(getkey) /* Find client entry */ client_entry = silc_idlist_get_client(client, conn, nickname, server, num, - TRUE); + FALSE); if (!client_entry) { - /* Client entry not found, it was requested thus mark this to be - pending command. */ - silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, - conn->cmd_ident, - silc_client_command_destructor, - silc_client_command_getkey, - silc_client_command_dup(cmd)); - cmd->pending = 1; - return; + /* Check whether user requested server actually */ + server_entry = silc_client_get_server(client, conn, nickname); + + if (!server_entry) { + /* No. what ever user wants we don't have it, so resolve it. We + will try to resolve both client and server, one of them is + bound to be wrong. */ + + /* This will send the IDENTIFY command */ + silc_idlist_get_client(client, conn, nickname, server, num, TRUE); + silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, + conn->cmd_ident, + silc_client_command_destructor, + silc_client_command_getkey, + silc_client_command_dup(cmd)); + + /* This sends the INFO command to resolve the server. */ + silc_client_send_command(client, conn, SILC_COMMAND_INFO, + ++conn->cmd_ident, 1, + 1, nickname, strlen(nickname)); + silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, + conn->cmd_ident, + silc_client_command_destructor, + silc_client_command_getkey, + silc_client_command_dup(cmd)); + + cmd->pending = 1; + return; + } + + idp = silc_id_payload_encode(server_entry->server_id, SILC_ID_SERVER); + } else { + idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT); } - idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT); buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1, 1, idp->data, idp->len); silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, diff --git a/lib/silcclient/command.h b/lib/silcclient/command.h index 10218167..79b42130 100644 --- a/lib/silcclient/command.h +++ b/lib/silcclient/command.h @@ -42,10 +42,8 @@ Flags for the command. These set how command behaves on different situations. Server sets these flags as well, but to be sure that our client never sends wrong commands we preserve the - flags on client side as well. - - XXX: We preserve these so that we define them but currently we - don't check the flags at all. + flags on client side as well (actually we preserve them but + ignore them :)). */ typedef struct { diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index b36e5446..a264ec24 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -431,13 +431,20 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd, SilcCommandStatus status) { SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; - SilcClientID *client_id; + SilcClient client = cmd->client; + SilcClientID *client_id = NULL; + SilcServerID *server_id = NULL; + SilcChannelID *channel_id = NULL; SilcIDCacheEntry id_cache = NULL; - SilcClientEntry client_entry = NULL; + SilcClientEntry client_entry; + SilcServerEntry server_entry; + SilcChannelEntry channel_entry; int argc; uint32 len; unsigned char *id_data; - char *nickname = NULL, *username = NULL; + char *name = NULL, *info = NULL; + SilcIDPayload idp = NULL; + SilcIdType id_type; argc = silc_argument_get_arg_num(cmd->args); @@ -446,59 +453,119 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd, COMMAND_REPLY_ERROR; return; } - - client_id = silc_id_payload_parse_id(id_data, len); - if (!client_id) { + idp = silc_id_payload_parse_data(id_data, len); + if (!idp) { COMMAND_REPLY_ERROR; return; } - - nickname = silc_argument_get_arg_type(cmd->args, 3, &len); - username = silc_argument_get_arg_type(cmd->args, 4, &len); - /* Check if we have this client cached already. */ - if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id, - NULL, NULL, - silc_hash_client_id_compare, NULL, - &id_cache)) { - SILC_LOG_DEBUG(("Adding new client entry")); + name = silc_argument_get_arg_type(cmd->args, 3, &len); + info = silc_argument_get_arg_type(cmd->args, 4, &len); - client_entry = silc_calloc(1, sizeof(*client_entry)); - client_entry->id = client_id; - silc_parse_nickname(nickname, &client_entry->nickname, - &client_entry->server, &client_entry->num); - if (username) - client_entry->username = strdup(username); - - /* Add client to cache */ - silc_idcache_add(conn->client_cache, client_entry->nickname, - client_id, (void *)client_entry, FALSE); - } else { - client_entry = (SilcClientEntry)id_cache->context; - if (client_entry->nickname) - silc_free(client_entry->nickname); - if (client_entry->server) - silc_free(client_entry->server); - if (username && client_entry->username) - silc_free(client_entry->username); - - SILC_LOG_DEBUG(("Updating client entry")); + id_type = silc_id_payload_get_type(idp); - silc_parse_nickname(nickname, &client_entry->nickname, - &client_entry->server, &client_entry->num); - - if (username) - client_entry->username = strdup(username); - - /* Remove the old cache entry and create a new one */ - silc_idcache_del_by_context(conn->client_cache, client_entry); - silc_idcache_add(conn->client_cache, client_entry->nickname, - client_entry->id, client_entry, FALSE); - silc_free(client_id); + switch (id_type) { + case SILC_ID_CLIENT: + client_id = silc_id_payload_get_id(idp); + + SILC_LOG_DEBUG(("Received client information")); + + /* Check if we have this client cached already. */ + if (!silc_idcache_find_by_id_one_ext(conn->client_cache, + (void *)client_id, + NULL, NULL, + silc_hash_client_id_compare, NULL, + &id_cache)) { + SILC_LOG_DEBUG(("Adding new client entry")); + + client_entry = silc_calloc(1, sizeof(*client_entry)); + client_entry->id = silc_id_dup(client_id, id_type); + silc_parse_nickname(name, &client_entry->nickname, + &client_entry->server, &client_entry->num); + if (info) + client_entry->username = strdup(info); + + /* Add client to cache */ + silc_idcache_add(conn->client_cache, client_entry->nickname, + client_entry->id, (void *)client_entry, FALSE); + } else { + client_entry = (SilcClientEntry)id_cache->context; + if (client_entry->nickname) + silc_free(client_entry->nickname); + if (client_entry->server) + silc_free(client_entry->server); + if (info && client_entry->username) + silc_free(client_entry->username); + + SILC_LOG_DEBUG(("Updating client entry")); + + silc_parse_nickname(name, &client_entry->nickname, + &client_entry->server, &client_entry->num); + + if (info) + client_entry->username = strdup(info); + + /* Remove the old cache entry and create a new one */ + silc_idcache_del_by_context(conn->client_cache, client_entry); + silc_idcache_add(conn->client_cache, client_entry->nickname, + client_entry->id, client_entry, FALSE); + } + + /* Notify application */ + COMMAND_REPLY((ARGS, client_entry, name, info)); + break; + + case SILC_ID_SERVER: + server_id = silc_id_payload_get_id(idp); + + SILC_LOG_DEBUG(("Received server information")); + + /* Check if we have this server cached already. */ + if (!silc_idcache_find_by_id_one(conn->server_cache, + (void *)server_id, &id_cache)) { + SILC_LOG_DEBUG(("Adding new server entry")); + + server_entry = silc_calloc(1, sizeof(*server_entry)); + server_entry->server_id = silc_id_dup(server_id, id_type); + server_entry->server_name = strdup(name); + if (info) + server_entry->server_info = strdup(info); + + /* Add server to cache */ + silc_idcache_add(conn->server_cache, server_entry->server_name, + server_entry->server_id, (void *)server_entry, FALSE); + } else { + server_entry = (SilcServerEntry)id_cache->context; + } + + /* Notify application */ + COMMAND_REPLY((ARGS, server_entry, name, info)); + break; + + case SILC_ID_CHANNEL: + channel_id = silc_id_payload_get_id(idp); + + SILC_LOG_DEBUG(("Received channel information")); + + /* Check if we have this channel cached already. */ + if (!silc_idcache_find_by_id_one(conn->channel_cache, + (void *)channel_id, &id_cache)) { + SILC_LOG_DEBUG(("Adding new channel entry")); + channel_entry = silc_client_new_channel_id(client, conn->sock, + name, 0, idp); + } else { + channel_entry = (SilcChannelEntry)id_cache->context; + } + + /* Notify application */ + COMMAND_REPLY((ARGS, channel_entry, name, info)); + break; } - /* Notify application */ - COMMAND_REPLY((ARGS, client_entry, nickname, username)); + silc_id_payload_free(idp); + silc_free(client_id); + silc_free(server_id); + silc_free(channel_id); } /* Received reply for IDENTIFY command. This maybe called several times @@ -1008,6 +1075,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(join) mode, idp); silc_id_payload_free(idp); + conn->current_channel = channel; + /* Get hmac */ hmac = silc_argument_get_arg_type(cmd->args, 11, NULL); if (hmac) { @@ -1662,22 +1731,30 @@ SILC_CLIENT_CMD_REPLY_FUNC(users) /* Get channel ID */ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); - if (!tmp) + if (!tmp) { + COMMAND_REPLY_ERROR; goto out; + } channel_id = silc_id_payload_parse_id(tmp, tmp_len); - if (!channel_id) + if (!channel_id) { + COMMAND_REPLY_ERROR; goto out; - + } + /* Get the list count */ tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len); - if (!tmp) + if (!tmp) { + COMMAND_REPLY_ERROR; goto out; + } SILC_GET32_MSB(list_count, tmp); /* Get Client ID list */ tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len); - if (!tmp) + if (!tmp) { + COMMAND_REPLY_ERROR; goto out; + } client_id_list = silc_buffer_alloc(tmp_len); silc_buffer_pull_tail(client_id_list, tmp_len); @@ -1685,8 +1762,10 @@ SILC_CLIENT_CMD_REPLY_FUNC(users) /* Get client mode list */ tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len); - if (!tmp) + if (!tmp) { + COMMAND_REPLY_ERROR; goto out; + } client_mode_list = silc_buffer_alloc(tmp_len); silc_buffer_pull_tail(client_mode_list, tmp_len); @@ -1695,10 +1774,18 @@ SILC_CLIENT_CMD_REPLY_FUNC(users) /* Get channel entry */ if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, &id_cache)) { - COMMAND_REPLY_ERROR; - goto out; + /* Resolve the channel from server */ + silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE); + + /* Register pending command callback. After we've received the channel + information we will reprocess this command reply by re-calling this + USERS command reply callback. */ + silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident, + NULL, silc_client_command_reply_users, cmd); + return; + } else { + channel = (SilcChannelEntry)id_cache->context; } - channel = (SilcChannelEntry)id_cache->context; /* Remove old client list from channel. */ silc_list_start(channel->clients); @@ -1707,9 +1794,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(users) silc_free(chu); } - /* Cache the received Client ID's and modes. This cache expires - whenever server sends notify message to channel. It means two things; - some user has joined or leaved the channel. XXX! */ + /* Cache the received Client ID's and modes. */ for (i = 0; i < list_count; i++) { uint16 idp_len; uint32 mode; @@ -1821,6 +1906,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(getkey) SilcIDPayload idp = NULL; SilcClientID *client_id = NULL; SilcClientEntry client_entry; + SilcServerID *server_id = NULL; + SilcServerEntry server_entry; SilcSKEPKType type; unsigned char *tmp, *pk; uint32 len; @@ -1865,8 +1952,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(getkey) id_type = silc_id_payload_get_type(idp); if (id_type == SILC_ID_CLIENT) { + /* Received client's public key */ client_id = silc_id_payload_get_id(idp); - if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id, NULL, NULL, @@ -1879,10 +1966,16 @@ SILC_CLIENT_CMD_REPLY_FUNC(getkey) /* Notify application */ COMMAND_REPLY((ARGS, id_type, client_entry, public_key)); } else if (id_type == SILC_ID_SERVER) { - /* XXX we don't have server entries at all */ - goto out; - } else { - goto out; + /* Received server's public key */ + server_id = silc_id_payload_get_id(idp); + if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id, + &id_cache)) + goto out; + + server_entry = (SilcServerEntry)id_cache->context; + + /* Notify application */ + COMMAND_REPLY((ARGS, id_type, server_entry, public_key)); } out: @@ -1892,5 +1985,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(getkey) if (public_key) silc_pkcs_public_key_free(public_key); silc_free(client_id); + silc_free(server_id); silc_client_command_reply_free(cmd); } diff --git a/lib/silcclient/idlist.c b/lib/silcclient/idlist.c index 6d865882..0599b405 100644 --- a/lib/silcclient/idlist.c +++ b/lib/silcclient/idlist.c @@ -298,7 +298,7 @@ void silc_client_get_clients_by_list(SilcClient client, (res_argc + 1)); res_argv[res_argc] = client_id_list->data; res_argv_lens[res_argc] = idp_len; - res_argv_types[res_argc] = res_argc + 3; + res_argv_types[res_argc] = res_argc + 5; res_argc++; } @@ -556,6 +556,134 @@ SilcChannelEntry silc_client_get_channel(SilcClient client, return entry; } +/* Finds entry for channel by the channel ID. Returns the entry or NULL + if the entry was not found. It is found only if the client is joined + to the channel. */ + +SilcChannelEntry silc_client_get_channel_by_id(SilcClient client, + SilcClientConnection conn, + SilcChannelID *channel_id) +{ + SilcIDCacheEntry id_cache; + SilcChannelEntry entry; + + if (!silc_idcache_find_by_id_one(conn->channel_cache, channel_id, + &id_cache)) + return NULL; + + entry = (SilcChannelEntry)id_cache->context; + + return entry; +} + +typedef struct { + SilcClient client; + SilcClientConnection conn; + SilcChannelID *channel_id; + SilcGetChannelCallback completion; + void *context; + int found; +} *GetChannelByIDInternal; + +SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback) +{ + GetChannelByIDInternal i = (GetChannelByIDInternal)context; + SilcChannelEntry entry; + + /* Get the channel */ + entry = silc_client_get_channel_by_id(i->client, i->conn, + i->channel_id); + if (entry) { + i->completion(i->client, i->conn, &entry, 1, i->context); + i->found = TRUE; + } +} + +static void silc_client_get_channel_by_id_destructor(void *context) +{ + GetChannelByIDInternal i = (GetChannelByIDInternal)context; + + if (i->found == FALSE) + i->completion(i->client, i->conn, NULL, 0, i->context); + + silc_free(i->channel_id); + silc_free(i); +} + +/* Resolves channel information from the server by the channel ID. */ + +void silc_client_get_channel_by_id_resolve(SilcClient client, + SilcClientConnection conn, + SilcChannelID *channel_id, + SilcGetChannelCallback completion, + void *context) +{ + SilcBuffer idp; + GetChannelByIDInternal i = silc_calloc(1, sizeof(*i)); + + idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL); + silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY, + ++conn->cmd_ident, + 1, 5, idp->data, idp->len); + silc_buffer_free(idp); + + i->client = client; + i->conn = conn; + i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL); + i->completion = completion; + i->context = context; + + /* Add pending callback */ + silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, + conn->cmd_ident, + silc_client_get_channel_by_id_destructor, + silc_client_command_get_channel_by_id_callback, + (void *)i); +} + +/* Find channel entry by ID. This routine is used internally by the library. */ + +SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client, + SilcClientConnection conn, + SilcChannelID *channel_id, + int query) +{ + SilcBuffer idp; + SilcChannelEntry channel; + + channel = silc_client_get_channel_by_id(client, conn, channel_id); + if (channel) + return channel; + + if (query) { + idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL); + silc_client_send_command(client, conn, SILC_COMMAND_IDENTIFY, + ++conn->cmd_ident, + 1, 5, idp->data, idp->len); + silc_buffer_free(idp); + } + + return NULL; +} + +/* Finds entry for server by the server name. */ + +SilcServerEntry silc_client_get_server(SilcClient client, + SilcClientConnection conn, + char *server_name) +{ + SilcIDCacheEntry id_cache; + SilcServerEntry entry; + + if (!silc_idcache_find_by_name_one(conn->server_cache, server_name, + &id_cache)) + return NULL; + + entry = (SilcServerEntry)id_cache->context; + + return entry; +} + /* Finds entry for server by the server ID. */ SilcServerEntry silc_client_get_server_by_id(SilcClient client, diff --git a/lib/silcclient/idlist.h b/lib/silcclient/idlist.h index 835da1aa..32088f15 100644 --- a/lib/silcclient/idlist.h +++ b/lib/silcclient/idlist.h @@ -88,7 +88,8 @@ typedef struct { SilcServerID *server_id; } *SilcServerEntry; -/* Prototypes (some functions are defined in the silcapi.h) */ +/* Prototypes. These are used only by the library. Application should not + call these directly. */ SilcClientEntry silc_idlist_get_client(SilcClient client, SilcClientConnection conn, @@ -96,5 +97,9 @@ SilcClientEntry silc_idlist_get_client(SilcClient client, char *server, uint32 num, int query); +SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client, + SilcClientConnection conn, + SilcChannelID *channel_id, + int query); #endif diff --git a/lib/silcclient/silcapi.h b/lib/silcclient/silcapi.h index 140f2f22..ed5c5f0f 100644 --- a/lib/silcclient/silcapi.h +++ b/lib/silcclient/silcapi.h @@ -325,6 +325,28 @@ typedef struct { } SilcClientOperations; /***/ +/****s* silcclient/SilcClientAPI/SilcClientParams + * + * NAME + * + * typedef struct { ... } SilcClientParams; + * + * DESCRIPTION + * + * Client parameters. This can be filled with proper values and + * given as argument to the silc_client_alloc function. The structure + * hold various parameters which affects the function of the client. + * + * SOURCE + */ +typedef struct { + /* Rekey timeout in seconds. The client will perform rekey in this + time interval. If set to zero, default value will be used. */ + unsigned int rekey_secs; +} SilcClientParams; +/***/ + + /* Initialization functions (client.c) */ /****f* silcclient/SilcClientAPI/silc_client_alloc @@ -332,6 +354,7 @@ typedef struct { * SYNOPSIS * * SilcClient silc_client_alloc(SilcClientOperations *ops, + * SilcClientParams *params, * void *application, * const char *silc_version); * @@ -345,7 +368,9 @@ typedef struct { * version string. * ***/ -SilcClient silc_client_alloc(SilcClientOperations *ops, void *application, +SilcClient silc_client_alloc(SilcClientOperations *ops, + SilcClientParams *params, + void *application, const char *silc_version); /****f* silcclient/SilcClientAPI/silc_client_free @@ -639,7 +664,7 @@ void silc_client_send_private_message(SilcClient client, * * Callback function given to the silc_client_get_client function. The * found entries are allocated into the `clients' array. The array must - * not be freed by the caller, the library will free it later. If the + * not be freed by the receiver, the library will free it later. If the * `clients' is NULL, no such clients exist in the SILC Network. * ***/ @@ -810,6 +835,30 @@ bool silc_client_del_client_by_id(SilcClient client, SilcClientConnection conn, SilcClientID *client_id); +/****f* silcclient/SilcClientAPI/SilcGetChannelCallback + * + * SYNOPSIS + * + * typedef void (*SilcGetClientCallback)(SilcClient client, + * SilcClientConnection conn, + * SilcClientEntry *clients, + * uint32 clients_count, + * void *context); + * + * DESCRIPTION + * + * Callback function given to the silc_client_get_channel_* functions. + * The found entries are allocated into the `channels' array. The array + * must not be freed by the receiver, the library will free it later. + * If the `channel' is NULL, no such channel exist in the SILC Network. + * + ***/ +typedef void (*SilcGetChannelCallback)(SilcClient client, + SilcClientConnection conn, + SilcChannelEntry *channels, + uint32 channels_count, + void *context); + /****f* silcclient/SilcClientAPI/silc_client_get_channel * * SYNOPSIS @@ -829,6 +878,69 @@ SilcChannelEntry silc_client_get_channel(SilcClient client, SilcClientConnection conn, char *channel); +/****f* silcclient/SilcClientAPI/silc_client_get_channel + * + * SYNOPSIS + * + * void + * silc_client_get_channel_by_id_resolve(SilcClient client, + * SilcClientConnection conn, + * SilcChannelID *channel_id, + * SilcGetClientCallback completion, + * void *context); + * + * DESCRIPTION + * + * Finds channel entry by the channel name. Returns the entry or NULL + * if it was not found. + * + ***/ +SilcChannelEntry silc_client_get_channel_by_id(SilcClient client, + SilcClientConnection conn, + SilcChannelID *channel_id); + +/****f* silcclient/SilcClientAPI/silc_client_get_channel + * + * SYNOPSIS + * + * void + * silc_client_get_channel_by_id_resolve(SilcClient client, + * SilcClientConnection conn, + * SilcChannelID *channel_id, + * SilcGetClientCallback completion, + * void *context); + * + * DESCRIPTION + * + * Resolves the channel information (its name mainly) from the server + * by the `channel_id'. Use this only if you know that you do not have + * the entry cached locally. + * + ***/ +void silc_client_get_channel_by_id_resolve(SilcClient client, + SilcClientConnection conn, + SilcChannelID *channel_id, + SilcGetChannelCallback completion, + void *context); + +/****f* silcclient/SilcClientAPI/silc_client_get_server + * + * SYNOPSIS + * + * SilcServerEntry silc_client_get_server(SilcClient client, + * SilcClientConnection conn, + * char *server_name) + * + * DESCRIPTION + * + * Finds entry for server by the server name. Returns the entry or NULL + * if the entry was not found. + * + ***/ +SilcServerEntry silc_client_get_server(SilcClient client, + SilcClientConnection conn, + char *server_name); + /****f* silcclient/SilcClientAPI/silc_client_get_server_by_id * * SYNOPSIS