From: Pekka Riikonen Date: Tue, 28 Nov 2006 20:29:06 +0000 (+0000) Subject: More client library rewrites. X-Git-Tag: silc.client.1.1.beta1~170 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=ce6ade69cd8e0aeca9ef097b2ceec9d43186d91f More client library rewrites. --- diff --git a/lib/silcclient/Makefile.ad b/lib/silcclient/Makefile.ad index a508a01a..1263c327 100644 --- a/lib/silcclient/Makefile.ad +++ b/lib/silcclient/Makefile.ad @@ -27,6 +27,7 @@ libsilcclient_la_SOURCES = \ client_connect.c \ client_register.c \ client_notify.c \ + client_attrs.c \ command.c \ command_reply.c diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 2d9e08a4..c0e8fa59 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -379,7 +379,7 @@ SILC_FSM_STATE(silc_client_disconnect) /* Call connection callback */ conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED, status, - message, conn->context); + message, conn->callback_context); silc_free(message); silc_packet_free(packet); @@ -441,11 +441,6 @@ silc_client_add_connection(SilcClient client, conn = silc_calloc(1, sizeof(*conn)); if (!conn) return NULL; - conn->internal = silc_calloc(1, sizeof(*conn->internal)); - if (!conn->internal) { - silc_free(conn); - return NULL; - } conn->client = client; conn->public_key = public_key; @@ -454,7 +449,21 @@ silc_client_add_connection(SilcClient client, conn->remote_port = port ? port : 706; conn->type = conn_type; conn->callback = callback; - conn->context = context; + conn->callback_context = context; + + conn->internal = silc_calloc(1, sizeof(*conn->internal)); + if (!conn->internal) { + silc_free(conn); + return NULL; + } + + if (!silc_hash_alloc("sha1", &conn->internal->sha1hash)) { + silc_free(conn); + silc_free(conn->internal); + return NULL; + } + if (params) + conn->internal->params = *params; conn->internal->verbose = TRUE; silc_list_init(conn->internal->pending_commands, struct SilcClientCommandContextStruct, next); @@ -474,14 +483,6 @@ silc_client_add_connection(SilcClient client, conn->internal->ftp_sessions = silc_dlist_init(); - if (params) { - if (params->detach_data) - conn->internal->params.detach_data = - silc_memdup(params->detach_data, - params->detach_data_len); - conn->internal->params.detach_data_len = params->detach_data_len; - } - /* Run the connection state machine. If threads are in use the machine is always run in a real thread. */ thread = silc_fsm_thread_alloc(&client->internal->fsm, conn, @@ -697,6 +698,14 @@ SilcBool silc_client_key_exchange(SilcClient client, return TRUE; } +/* Closes remote connection */ + +void silc_client_close_connection(SilcClient client, + SilcClientConnection conn) +{ + +} + #if 0 /* Finalizes the connection to the remote SILC server. This is called after authentication protocol has been completed. This send our @@ -1031,10 +1040,6 @@ void silc_client_free(SilcClient client) silc_hmac_unregister_all(); } - silc_hash_free(client->md5hash); - silc_hash_free(client->sha1hash); - silc_hmac_free(client->internal->md5hmac); - silc_hmac_free(client->internal->sha1hmac); silc_free(client->internal->params); silc_free(client->internal->silc_client_version); silc_free(client->internal); @@ -1046,37 +1051,46 @@ void silc_client_free(SilcClient client) the client ready to be run. One must call silc_client_run to run the client. Returns FALSE if error occured, TRUE otherwise. */ -SilcBool silc_client_init(SilcClient client) +SilcBool silc_client_init(SilcClient client, const char *username, + const char *hostname, const char *realname) { SILC_LOG_DEBUG(("Initializing client")); - assert(client); - assert(client->username); - assert(client->hostname); - assert(client->realname); + if (!client) + return FALSE; + + if (!username || !hostname || !realname) { + SILC_LOG_ERROR(("Username, hostname and realname must be given to " + "silc_client_init")); + return FALSE; + } /* Validate essential strings */ - if (client->nickname) - if (!silc_identifier_verify(client->nickname, strlen(client->nickname), - SILC_STRING_UTF8, 128)) { - SILC_LOG_ERROR(("Malformed nickname '%s'", client->nickname)); - return FALSE; - } - if (!silc_identifier_verify(client->username, strlen(client->username), + if (!silc_identifier_verify(username, strlen(username), SILC_STRING_UTF8, 128)) { - SILC_LOG_ERROR(("Malformed username '%s'", client->username)); + SILC_LOG_ERROR(("Malformed username '%s'. Username must be UTF-8 string", + client->username)); return FALSE; } - if (!silc_identifier_verify(client->hostname, strlen(client->hostname), + if (!silc_identifier_verify(hostname, strlen(hostname), SILC_STRING_UTF8, 256)) { - SILC_LOG_ERROR(("Malformed hostname '%s'", client->hostname)); + SILC_LOG_ERROR(("Malformed hostname '%s'. Hostname must be UTF-8 string", + client->hostname)); return FALSE; } - if (!silc_utf8_valid(client->realname, strlen(client->realname))) { - SILC_LOG_ERROR(("Malformed realname '%s'", client->realname)); + if (!silc_utf8_valid(realname, strlen(realname))) { + SILC_LOG_ERROR(("Malformed realname '%s'. Realname must be UTF-8 string", + client->realname)); return FALSE; } + /* Take the name strings */ + client->username = strdup(username); + client->hostname = strdup(hostname); + client->realname = strdup(realname); + if (!username || !hostname || !realname) + return FALSE; + if (!client->internal->params->dont_register_crypto_library) { /* Initialize the crypto library. If application has done this already this has no effect. Also, we will not be overriding something @@ -1087,10 +1101,6 @@ SilcBool silc_client_init(SilcClient client) silc_hmac_register_default(); } - /* Initialize hash functions for client to use */ - silc_hash_alloc("md5", &client->md5hash); - silc_hash_alloc("sha1", &client->sha1hash); - /* Initialize random number generator */ client->rng = silc_rng_alloc(); silc_rng_init(client->rng); @@ -1099,7 +1109,7 @@ SilcBool silc_client_init(SilcClient client) /* Initialize the scheduler */ client->schedule = silc_schedule_init(client->internal->params->task_max ? - client->internal->params->task_max : 200, client); + client->internal->params->task_max : 0, client); if (!client->schedule) return FALSE; @@ -1122,6 +1132,13 @@ SilcBool silc_client_init(SilcClient client) /* Register commands */ silc_client_commands_register(client); + /* Start the client machine */ + silc_fsm_start_sync(&client->internal->fsm, silc_client_st_run); + + /* Signal the application when we are running */ + client->internal->run_callback = TRUE; + SILC_FSM_SEMA_POST(&client->internal->wait_event); + return TRUE; } @@ -1134,7 +1151,6 @@ void silc_client_stop(SilcClient client) silc_schedule_stop(client->schedule); silc_schedule_uninit(client->schedule); - silc_client_commands_unregister(client); SILC_LOG_DEBUG(("Client stopped")); @@ -1147,13 +1163,6 @@ void silc_client_run(SilcClient client) { SILC_LOG_DEBUG(("Starting SILC client")); - /* Start the client */ - silc_fsm_start_sync(&client->internal->fsm, silc_client_st_run); - - /* Signal the application when we are running */ - client->internal->run_callback = TRUE; - SILC_FSM_SEMA_POST(&client->internal->wait_event); - /* Run the scheduler */ silc_schedule(client->schedule); } diff --git a/lib/silcclient/client.h b/lib/silcclient/client.h index 1f3d0d2b..d60b740a 100644 --- a/lib/silcclient/client.h +++ b/lib/silcclient/client.h @@ -78,7 +78,12 @@ typedef struct SilcChannelEntryInternalStruct { SilcHmac hmac; /* Current HMAC */ unsigned char iv[SILC_CIPHER_MAX_IV_SIZE]; /* Current IV */ - SilcUInt16 resolve_cmd_ident; /* Resolving identifier */ + SilcUInt16 resolve_cmd_ident; /* Channel information resolving + identifier. This is used when + resolving users, and other + stuff that relates to the + channel. Not used for the + channel resolving itself. */ SilcAtomic8 refcnt; /* Reference counter */ } SilcChannelEntryInternal; diff --git a/lib/silcclient/client_attrs.c b/lib/silcclient/client_attrs.c index 207e34eb..bee7ca74 100644 --- a/lib/silcclient/client_attrs.c +++ b/lib/silcclient/client_attrs.c @@ -94,7 +94,7 @@ SilcBuffer silc_client_attributes_process(SilcClient client, /* Always put our public key. */ pk.type = "silc-rsa"; - pk.data = silc_pkcs_public_key_encode(client->public_key, &pk.data_len); + pk.data = silc_pkcs_public_key_encode(conn->public_key, &pk.data_len); buffer = silc_attribute_payload_encode(buffer, SILC_ATTRIBUTE_USER_PUBLIC_KEY, pk.data ? SILC_ATTRIBUTE_FLAG_VALID : @@ -121,9 +121,9 @@ SilcBuffer silc_client_attributes_process(SilcClient client, buffer = f.buffer; /* Finally compute the digital signature of all the data we provided. */ - if (silc_pkcs_sign_with_hash(client->pkcs, client->sha1hash, - buffer->data, buffer->len, - sign, &sign_len)) { + if (silc_pkcs_sign(conn->private_key, silc_buffer_data(buffer), + silc_buffer_len(buffer), sign, sizeof(sign), &sign_len, + conn->internal->sha1hash)) { pk.type = NULL; pk.data = sign; pk.data_len = sign_len; diff --git a/lib/silcclient/client_channel.c b/lib/silcclient/client_channel.c index c843b63b..37cd5a78 100644 --- a/lib/silcclient/client_channel.c +++ b/lib/silcclient/client_channel.c @@ -480,7 +480,7 @@ SilcBool silc_client_add_channel_private_key(SilcClient client, /* Produce the key material */ keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16, - client->sha1hash); + conn->internal->sha1hash); if (!keymat) return FALSE; @@ -670,7 +670,8 @@ SilcChannelUser silc_client_on_channel(SilcChannelEntry channel, return NULL; } -/* Adds client to channel */ +/* Adds client to channel. Returns TRUE if user was added or is already + added to the channel, FALSE on error. */ SilcBool silc_client_add_to_channel(SilcChannelEntry channel, SilcClientEntry client_entry, @@ -679,7 +680,7 @@ SilcBool silc_client_add_to_channel(SilcChannelEntry channel, SilcChannelUser chu; if (silc_client_on_channel(channel, client_entry)) - return FALSE; + return TRUE; chu = silc_calloc(1, sizeof(*chu)); if (!chu) diff --git a/lib/silcclient/client_connect.c b/lib/silcclient/client_connect.c index bef89fa5..3b656229 100644 --- a/lib/silcclient/client_connect.c +++ b/lib/silcclient/client_connect.c @@ -89,7 +89,7 @@ static void silc_client_connect_callback(SilcNetStatus status, /* Notify application of failure */ SILC_LOG_DEBUG(("Connecting failed")); conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, - NULL, conn->context); + NULL, conn->callback_context); silc_fsm_next(fsm, silc_client_st_connect_error); SILC_FSM_CALL_CONTINUE(fsm); return; @@ -204,7 +204,7 @@ static void silc_client_ke_completion(SilcSKE ske, conn->remote_host); conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_KE, 0, NULL, - conn->context); + conn->callback_context); silc_fsm_next(fsm, silc_client_st_connect_error); SILC_FSM_CALL_CONTINUE(fsm); @@ -260,7 +260,7 @@ static void silc_client_connect_auth_completion(SilcConnAuth connauth, "Authentication failed"); conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_AUTH, 0, NULL, - conn->context); + conn->callback_context); silc_fsm_next(fsm, silc_client_st_connect_error); } @@ -289,7 +289,7 @@ SILC_FSM_STATE(silc_client_st_connect) /** IP address not given */ SILC_LOG_ERROR(("Local UDP IP address not specified")); conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL, - conn->context); + conn->callback_context); silc_fsm_next(fsm, silc_client_st_connect_error); return SILC_FSM_CONTINUE; } @@ -327,7 +327,7 @@ SILC_FSM_STATE(silc_client_st_connect_set_stream) /** Cannot create packet stream */ SILC_LOG_DEBUG(("Could not create packet stream")); conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL, - conn->context); + conn->callback_context); silc_fsm_next(fsm, silc_client_st_connect_error); return SILC_FSM_CONTINUE; } @@ -357,7 +357,7 @@ SILC_FSM_STATE(silc_client_st_connect_key_exchange) if (!conn->internal->ske) { /** Out of memory */ conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_KE, 0, NULL, - conn->context); + conn->callback_context); silc_fsm_next(fsm, silc_client_st_connect_error); return SILC_FSM_CONTINUE; } @@ -411,7 +411,7 @@ SILC_FSM_STATE(silc_client_st_connect_setup_udp) if (!stream) { /** Cannot create UDP stream */ conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL, - conn->context); + conn->callback_context); silc_fsm_next(fsm, silc_client_st_connect_error); return SILC_FSM_CONTINUE; } @@ -474,7 +474,7 @@ SILC_FSM_STATE(silc_client_st_connect_auth_start) if (!connauth) { /** Out of memory */ conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_AUTH, 0, NULL, - conn->context); + conn->callback_context); silc_fsm_next(fsm, silc_client_st_connect_error); return SILC_FSM_CONTINUE; } @@ -517,7 +517,7 @@ SILC_FSM_STATE(silc_client_st_connected) /* Call connection callback */ conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL, - conn->context); + conn->callback_context); return SILC_FSM_FINISH; } diff --git a/lib/silcclient/client_entry.c b/lib/silcclient/client_entry.c index ce3717aa..23c3c728 100644 --- a/lib/silcclient/client_entry.c +++ b/lib/silcclient/client_entry.c @@ -186,12 +186,13 @@ static SilcBool silc_client_get_clients_cb(SilcClient client, /* Resolves client information from server by the client ID. */ -void silc_client_get_client_by_id_resolve(SilcClient client, - SilcClientConnection conn, - SilcClientID *client_id, - SilcBuffer attributes, - SilcGetClientCallback completion, - void *context) +SilcUInt16 +silc_client_get_client_by_id_resolve(SilcClient client, + SilcClientConnection conn, + SilcClientID *client_id, + SilcBuffer attributes, + SilcGetClientCallback completion, + void *context) { SilcClientGetClientInternal i; SilcClientEntry client_entry; @@ -199,20 +200,20 @@ void silc_client_get_client_by_id_resolve(SilcClient client, SilcUInt16 cmd_ident; if (!client || !conn | !client_id) - return; + return 0; SILC_LOG_DEBUG(("Resolve client by ID (%s)", silc_id_render(client_id, SILC_ID_CLIENT))); i = silc_calloc(1, sizeof(*i)); if (!i) - return; + return 0; i->completion = completion; i->context = context; i->clients = silc_dlist_init(); if (!i->clients) { silc_free(i); - return; + return 0; } /* Attach to resolving, if on going */ @@ -223,7 +224,7 @@ void silc_client_get_client_by_id_resolve(SilcClient client, silc_client_command_pending(conn, SILC_COMMAND_NONE, client_entry->internal.resolve_cmd_ident, silc_client_get_clients_cb, i); - return; + return client_entry->internal.resolve_cmd_ident; } /* Send the command */ @@ -232,7 +233,7 @@ void silc_client_get_client_by_id_resolve(SilcClient client, silc_client_get_clients_cb, i, 2, 3, silc_buffer_datalen(attributes), 4, silc_buffer_datalen(idp)); - if (!cmd_ident) + if (!cmd_ident && completion) completion(client, conn, SILC_STATUS_ERR_RESOURCE_LIMIT, NULL, context); if (client_entry && cmd_ident) @@ -240,6 +241,8 @@ void silc_client_get_client_by_id_resolve(SilcClient client, silc_client_unref_client(client, conn, client_entry); silc_buffer_free(idp); + + return cmd_ident; } /* Finds client entry or entries by the `nickname' and `server'. The @@ -404,29 +407,29 @@ static SilcBool silc_client_get_clients_list_cb(SilcClient client, command reply for example returns this sort of list. The `completion' will be called after the entries are available. */ -void silc_client_get_clients_by_list(SilcClient client, - SilcClientConnection conn, - SilcUInt32 list_count, - SilcBuffer client_id_list, - SilcGetClientCallback completion, - void *context) +SilcUInt16 silc_client_get_clients_by_list(SilcClient client, + SilcClientConnection conn, + SilcUInt32 list_count, + SilcBuffer client_id_list, + SilcGetClientCallback completion, + void *context) { GetClientsByListInternal in; SilcClientEntry entry; unsigned char **res_argv = NULL; SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0; - SilcUInt16 idp_len; + SilcUInt16 idp_len, cmd_ident; SilcID id; int i; SILC_LOG_DEBUG(("Resolve clients from Client ID list")); if (!client || !conn || !client_id_list) - return; + return 0; in = silc_calloc(1, sizeof(*in)); if (!in) - return; + return 0; in->completion = completion; in->context = context; in->list_count = list_count; @@ -470,20 +473,22 @@ void silc_client_get_clients_by_list(SilcClient client, /* Query the unknown client information from server */ if (res_argc) { - silc_client_command_send_argv(client, conn, SILC_COMMAND_WHOIS, - silc_client_get_clients_list_cb, - in, res_argc, res_argv, res_argv_lens, - res_argv_types); + cmd_ident = silc_client_command_send_argv(client, + conn, SILC_COMMAND_WHOIS, + silc_client_get_clients_list_cb, + in, res_argc, res_argv, + res_argv_lens, + res_argv_types); silc_free(res_argv); silc_free(res_argv_lens); silc_free(res_argv_types); - return; + return cmd_ident; } /* We have the clients in cache, get them and call the completion */ silc_client_get_clients_list_cb(client, conn, SILC_COMMAND_WHOIS, SILC_STATUS_OK, SILC_STATUS_OK, in, NULL); - return; + return 0; err: silc_buffer_free(in->client_id_list); @@ -491,6 +496,7 @@ void silc_client_get_clients_by_list(SilcClient client, silc_free(res_argv); silc_free(res_argv_lens); silc_free(res_argv_types); + return 0; } #if 0 @@ -1179,17 +1185,20 @@ void silc_client_get_channel_resolve(SilcClient client, /* Send the command */ if (!silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, silc_client_get_channel_cb, i, 1, - 3, channel_name, strlen(channel_name))) - completion(client, conn, SILC_STATUS_ERR_RESOURCE_LIMIT, NULL, context); + 3, channel_name, strlen(channel_name))) { + if (completion) + completion(client, conn, SILC_STATUS_ERR_RESOURCE_LIMIT, NULL, context); + } } /* 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) +SilcUInt16 +silc_client_get_channel_by_id_resolve(SilcClient client, + SilcClientConnection conn, + SilcChannelID *channel_id, + SilcGetChannelCallback completion, + void *context) { SilcClientGetChannelInternal i; SilcChannelEntry channel; @@ -1197,31 +1206,20 @@ void silc_client_get_channel_by_id_resolve(SilcClient client, SilcUInt16 cmd_ident; if (!client || !conn || !channel_id || !completion) - return; + return 0; SILC_LOG_DEBUG(("Resolve channel by id %s", silc_id_render(channel_id, SILC_ID_CHANNEL))); i = silc_calloc(1, sizeof(*i)); if (!i) - return; + return 0; i->completion = completion; i->context = context; i->channels = silc_dlist_init(); if (!i->channels) { silc_free(i); - return; - } - - /* Attach to resolving, if on going */ - channel = silc_client_get_channel_by_id(client, conn, channel_id); - if (channel && channel->internal.resolve_cmd_ident) { - SILC_LOG_DEBUG(("Attach to existing resolving")); - silc_client_unref_channel(client, conn, channel); - silc_client_command_pending(conn, SILC_COMMAND_NONE, - channel->internal.resolve_cmd_ident, - silc_client_get_channel_cb, i); - return; + return 0; } /* Send the command */ @@ -1230,13 +1228,12 @@ void silc_client_get_channel_by_id_resolve(SilcClient client, silc_client_get_channel_cb, i, 1, 5, silc_buffer_datalen(idp)); silc_buffer_free(idp); - if (!cmd_ident) + if (!cmd_ident && completion) completion(client, conn, SILC_STATUS_ERR_RESOURCE_LIMIT, NULL, context); - if (channel && cmd_ident) - channel->internal.resolve_cmd_ident = cmd_ident; - silc_client_unref_channel(client, conn, channel); + + return cmd_ident; } /************************* Channel Entry Routines ***************************/ @@ -1285,6 +1282,8 @@ SilcChannelEntry silc_client_add_channel(SilcClient client, return NULL; } + silc_mutex_lock(conn->internal->lock); + /* Add channel to cache, the normalized channel name is saved to cache */ if (!silc_idcache_add(conn->internal->channel_cache, channel_namec, &channel->id, channel)) { @@ -1292,9 +1291,12 @@ SilcChannelEntry silc_client_add_channel(SilcClient client, silc_free(channel->channel_name); silc_hash_table_free(channel->user_list); silc_free(channel); + silc_mutex_unlock(conn->internal->lock); return NULL; } + silc_mutex_unlock(conn->internal->lock); + return channel; } @@ -1490,13 +1492,13 @@ SilcServerEntry silc_client_get_server_by_id(SilcClient client, silc_mutex_lock(conn->internal->lock); if (!silc_idcache_find_by_id_one(conn->internal->server_cache, - (void *)server_id, &id_cache)) + server_id, &id_cache)) return NULL; SILC_LOG_DEBUG(("Found")); /* Reference */ - entry = (SilcServerEntry)id_cache->context; + entry = id_cache->context; silc_client_ref_server(client, conn, entry); silc_mutex_unlock(conn->internal->lock); @@ -1561,11 +1563,12 @@ static SilcBool silc_client_get_server_cb(SilcClient client, /* Resolve server by server ID */ -void silc_client_get_server_by_id_resolve(SilcClient client, - SilcClientConnection conn, - SilcServerID *server_id, - SilcGetServerCallback completion, - void *context) +SilcUInt16 +silc_client_get_server_by_id_resolve(SilcClient client, + SilcClientConnection conn, + SilcServerID *server_id, + SilcGetServerCallback completion, + void *context) { SilcClientGetServerInternal i; SilcServerEntry server; @@ -1573,20 +1576,20 @@ void silc_client_get_server_by_id_resolve(SilcClient client, SilcUInt16 cmd_ident; if (!client || !conn || !server_id || !completion) - return; + return 0; SILC_LOG_DEBUG(("Resolve server by id %s", silc_id_render(server_id, SILC_ID_SERVER))); i = silc_calloc(1, sizeof(*i)); if (!i) - return; + return 0; i->completion = completion; i->context = context; i->servers = silc_dlist_init(); if (!i->servers) { silc_free(i); - return; + return 0; } /* Attach to resolving, if on going */ @@ -1597,7 +1600,7 @@ void silc_client_get_server_by_id_resolve(SilcClient client, silc_client_command_pending(conn, SILC_COMMAND_NONE, server->internal.resolve_cmd_ident, silc_client_get_server_cb, i); - return; + return server->internal.resolve_cmd_ident; } /* Send the command */ @@ -1606,13 +1609,15 @@ void silc_client_get_server_by_id_resolve(SilcClient client, silc_client_get_server_cb, i, 1, 5, silc_buffer_datalen(idp)); silc_buffer_free(idp); - if (!cmd_ident) + if (!cmd_ident && completion) completion(client, conn, SILC_STATUS_ERR_RESOURCE_LIMIT, NULL, context); if (server && cmd_ident) server->internal.resolve_cmd_ident = cmd_ident; silc_client_unref_server(client, conn, server); + + return cmd_ident; } /************************** Server Entry Routines ***************************/ diff --git a/lib/silcclient/client_internal.h b/lib/silcclient/client_internal.h index 99a28733..51c18227 100644 --- a/lib/silcclient/client_internal.h +++ b/lib/silcclient/client_internal.h @@ -130,10 +130,6 @@ struct SilcClientInternalStruct { /* Registered commands */ SilcList commands; - /* Generic cipher and hash objects. */ - SilcHmac md5hmac; - SilcHmac sha1hmac; - /* Client version. Used to compare to remote host's version strings. */ char *silc_client_version; @@ -143,44 +139,29 @@ struct SilcClientInternalStruct { /* Internal context for conn->internal in SilcClientConnection. */ struct SilcClientConnectionInternalStruct { - /* Client ID and Channel ID cache. Messages transmitted in SILC network - are done using different unique ID's. These are the cache for - thoses ID's used in the communication. */ - SilcIDCache client_cache; - SilcIDCache channel_cache; - SilcIDCache server_cache; - - /* Pending command queue for this connection */ - SilcList pending_commands; - - /* Set away message */ - SilcClientAway *away; - - /* Authentication request context. */ - SilcClientConnAuthRequest connauth; - - /* File transmission sessions */ - SilcDList ftp_sessions; - SilcUInt32 next_session_id; - SilcClientFtpSession active_session; - - /* Requested Attributes */ - SilcHashTable attrs; + SilcIDCacheEntry local_entry; /* Local client cache entry */ + SilcClientConnectionParams params; /* Connection parameters */ SilcFSMStruct fsm; /* Connection FSM */ SilcFSMThreadStruct event_thread; /* FSM thread for events */ SilcFSMSemaStruct wait_event; /* Event signaller */ - SilcMutex lock; /* Connection lock */ SilcSchedule schedule; /* Connection's scheduler */ + SilcMutex lock; /* Connection lock */ SilcSKE ske; /* Key exchange protocol */ SilcSKERekeyMaterial rekey; /* Rekey material */ - SilcHash hash; /* Negotiated hash function */ - SilcClientConnectionParams params; /* Connection parameters */ - SilcAtomic16 cmd_ident; /* Current command identifier */ - SilcIDCacheEntry local_entry; /* Local client cache entry */ SilcList thread_pool; /* Packet thread pool */ + SilcList pending_commands; /* Pending commands list */ + SilcHash hash; /* Negotiated hash function */ + SilcHash sha1hash; /* SHA-1 default hash context */ - SilcHashTable privmsg_wait; /* Waited private messages */ + SilcIDCache client_cache; /* Client entry cache */ + SilcIDCache channel_cache; /* Channel entry cache */ + SilcIDCache server_cache; /* Server entry cache */ + + SilcBuffer local_idp; /* Local ID Payload */ + SilcBuffer remote_idp; /* Remote ID Payload */ + + SilcAtomic16 cmd_ident; /* Current command identifier */ /* Events */ unsigned int connect : 1; /* Connect remote host */ @@ -190,6 +171,14 @@ struct SilcClientConnectionInternalStruct { /* Flags */ unsigned int verbose : 1; /* Notify application */ unsigned int registering : 1; /* Set when registering to network */ + + SilcClientAway *away; + SilcClientConnAuthRequest connauth; + SilcDList ftp_sessions; + SilcUInt32 next_session_id; + SilcClientFtpSession active_session; + SilcHashTable attrs; + SilcHashTable privmsg_wait; /* Waited private messages */ }; SILC_FSM_STATE(silc_client_connection_st_run); diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index d54e6ccc..9087ba35 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -26,6 +26,14 @@ #define NOTIFY conn->client->internal->ops->notify +/* Notify processing context */ +typedef struct { + SilcPacket packet; + SilcNotifyPayload payload; + SilcFSMThread fsm; + SilcChannelEntry channel; +} *SilcClientNotify; + /************************ Static utility functions **************************/ /* Entry resolving callback. This will continue processing the notify. */ @@ -36,12 +44,40 @@ static void silc_client_notify_resolved(SilcClient client, SilcDList entries, void *context) { + SilcClientNotify notify = context; + /* If no entries found, just finish the notify processing, a silent error */ if (!entries) - silc_fsm_next(context, silc_client_notify_processed); + silc_fsm_next(notify->fsm, silc_client_notify_processed); + + if (notify->channel) { + notify->channel->internal.resolve_cmd_ident = 0; + silc_client_unref_channel(client, conn, notify->channel); + } /* Continue processing the notify */ - SILC_FSM_CALL_CONTINUE_SYNC(context); + SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm); +} + +/* Continue notify processing after it was suspended while waiting for + channel information being resolved. */ + +static SilcBool silc_client_notify_wait_continue(SilcClient client, + SilcClientConnection conn, + SilcCommand command, + SilcStatus status, + SilcStatus error, + void *context, + va_list ap) +{ + SilcClientNotify notify = context; + + /* Continue after last command reply received */ + if (SILC_STATUS_IS_ERROR(status) || status == SILC_STATUS_OK || + status == SILC_STATUS_LIST_END) + SILC_FSM_CALL_CONTINUE(notify->fsm); + + return TRUE; } /********************************* Notify ***********************************/ @@ -51,6 +87,7 @@ static void silc_client_notify_resolved(SilcClient client, SILC_FSM_STATE(silc_client_notify) { SilcPacket packet = state_context; + SilcClientNotify notify; SilcNotifyPayload payload; payload = silc_notify_payload_parse(silc_buffer_data(&packet->buffer), @@ -68,8 +105,18 @@ SILC_FSM_STATE(silc_client_notify) return SILC_FSM_FINISH; } + notify = silc_calloc(1, sizeof(*notify)); + if (!notify) { + silc_notify_payload_free(payload); + silc_packet_free(packet); + return SILC_FSM_FINISH; + } + /* Save notify payload to packet context during processing */ - packet->next = (void *)payload; + notify->packet = packet; + notify->payload = payload; + notify->fsm = fsm; + silc_fsm_set_state_context(fsm, notify); /* Process the notify */ switch (silc_notify_get_type(payload)) { @@ -158,6 +205,7 @@ SILC_FSM_STATE(silc_client_notify) /** Unknown notify */ silc_notify_payload_free(payload); silc_packet_free(packet); + silc_free(notify); return SILC_FSM_FINISH; break; } @@ -169,10 +217,13 @@ SILC_FSM_STATE(silc_client_notify) SILC_FSM_STATE(silc_client_notify_processed) { - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcPacket packet = notify->packet; + SilcNotifyPayload payload = notify->payload; + silc_notify_payload_free(payload); silc_packet_free(packet); + silc_free(notify); return SILC_FSM_FINISH; } @@ -182,8 +233,8 @@ SILC_FSM_STATE(silc_client_notify_none) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); @@ -203,8 +254,8 @@ SILC_FSM_STATE(silc_client_notify_invite) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry; @@ -227,6 +278,17 @@ SILC_FSM_STATE(silc_client_notify_invite) /* Get the channel entry */ channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id); + /* If channel is being resolved handle notify after resolving */ + if (channel->internal.resolve_cmd_ident) { + silc_client_unref_channel(client, conn, channel); + SILC_FSM_CALL(silc_client_command_pending( + conn, SILC_COMMAND_NONE, + channel->internal.resolve_cmd_ident, + silc_client_notify_wait_continue, + fsm)); + /* NOT REACHED */ + } + /* Get sender Client ID */ if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) goto out; @@ -236,7 +298,9 @@ SILC_FSM_STATE(silc_client_notify_invite) if (!client_entry || !client_entry->nickname[0]) { /** Resolve client */ silc_client_unref_client(client, conn, client_entry); - SILC_FSM_CALL(silc_client_get_client_by_id_resolve( + notify->channel = channel; + SILC_FSM_CALL(channel->internal.resolve_cmd_ident = + silc_client_get_client_by_id_resolve( client, conn, &id.u.client_id, NULL, silc_client_notify_resolved, fsm)); @@ -263,8 +327,8 @@ SILC_FSM_STATE(silc_client_notify_join) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry; @@ -282,6 +346,17 @@ SILC_FSM_STATE(silc_client_notify_join) if (!channel) goto out; + /* If channel is being resolved handle notify after resolving */ + if (channel->internal.resolve_cmd_ident) { + silc_client_unref_channel(client, conn, channel); + SILC_FSM_CALL(silc_client_command_pending( + conn, SILC_COMMAND_NONE, + channel->internal.resolve_cmd_ident, + silc_client_notify_wait_continue, + fsm)); + /* NOT REACHED */ + } + /* Get Client ID */ if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) goto out; @@ -292,7 +367,9 @@ SILC_FSM_STATE(silc_client_notify_join) !client_entry->username[0]) { /** Resolve client */ silc_client_unref_client(client, conn, client_entry); - SILC_FSM_CALL(silc_client_get_client_by_id_resolve( + notify->channel = channel; + SILC_FSM_CALL(channel->internal.resolve_cmd_ident = + silc_client_get_client_by_id_resolve( client, conn, &id.u.client_id, NULL, silc_client_notify_resolved, fsm)); @@ -303,7 +380,8 @@ SILC_FSM_STATE(silc_client_notify_join) silc_client_nickname_format(client, conn, client_entry); /* Join the client to channel */ - silc_client_add_to_channel(channel, client_entry, 0); + if (!silc_client_add_to_channel(channel, client_entry, 0)) + goto out; /* Notify application. */ NOTIFY(client, conn, type, client_entry, channel); @@ -325,8 +403,9 @@ SILC_FSM_STATE(silc_client_notify_leave) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; + SilcPacket packet = notify->packet; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry = NULL; @@ -344,6 +423,17 @@ SILC_FSM_STATE(silc_client_notify_leave) if (!channel) goto out; + /* If channel is being resolved handle notify after resolving */ + if (channel->internal.resolve_cmd_ident) { + silc_client_unref_channel(client, conn, channel); + SILC_FSM_CALL(silc_client_command_pending( + conn, SILC_COMMAND_NONE, + channel->internal.resolve_cmd_ident, + silc_client_notify_wait_continue, + fsm)); + /* NOT REACHED */ + } + /* Get Client ID */ if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) goto out; @@ -399,8 +489,8 @@ SILC_FSM_STATE(silc_client_notify_signoff) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry; @@ -453,8 +543,9 @@ SILC_FSM_STATE(silc_client_notify_topic_set) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; + SilcPacket packet = notify->packet; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry = NULL; @@ -475,6 +566,17 @@ SILC_FSM_STATE(silc_client_notify_topic_set) if (!channel) goto out; + /* If channel is being resolved handle notify after resolving */ + if (channel->internal.resolve_cmd_ident) { + silc_client_unref_channel(client, conn, channel); + SILC_FSM_CALL(silc_client_command_pending( + conn, SILC_COMMAND_NONE, + channel->internal.resolve_cmd_ident, + silc_client_notify_wait_continue, + fsm)); + /* NOT REACHED */ + } + /* Get ID */ if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) goto out; @@ -490,7 +592,9 @@ SILC_FSM_STATE(silc_client_notify_topic_set) if (!client_entry || !client_entry->nickname[0]) { /** Resolve client */ silc_client_unref_client(client, conn, client_entry); - SILC_FSM_CALL(silc_client_get_client_by_id_resolve( + notify->channel = channel; + SILC_FSM_CALL(channel->internal.resolve_cmd_ident = + silc_client_get_client_by_id_resolve( client, conn, &id.u.client_id, NULL, silc_client_notify_resolved, fsm)); @@ -502,7 +606,9 @@ SILC_FSM_STATE(silc_client_notify_topic_set) server = silc_client_get_server_by_id(client, conn, &id.u.server_id); if (!server) { /** Resolve server */ - SILC_FSM_CALL(silc_client_get_server_by_id_resolve( + notify->channel = channel; + SILC_FSM_CALL(channel->internal.resolve_cmd_ident = + silc_client_get_server_by_id_resolve( client, conn, &id.u.server_id, silc_client_notify_resolved, fsm)); @@ -515,7 +621,9 @@ SILC_FSM_STATE(silc_client_notify_topic_set) &id.u.channel_id); if (!channel_entry) { /** Resolve channel */ - SILC_FSM_CALL(silc_client_get_channel_by_id_resolve( + notify->channel = channel; + SILC_FSM_CALL(channel->internal.resolve_cmd_ident = + silc_client_get_channel_by_id_resolve( client, conn, &id.u.channel_id, silc_client_notify_resolved, fsm)); @@ -552,8 +660,8 @@ SILC_FSM_STATE(silc_client_notify_nick_change) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry = NULL; @@ -640,8 +748,9 @@ SILC_FSM_STATE(silc_client_notify_cmode_change) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; + SilcPacket packet = notify->packet; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry = NULL; @@ -665,6 +774,17 @@ SILC_FSM_STATE(silc_client_notify_cmode_change) if (!channel) goto out; + /* If channel is being resolved handle notify after resolving */ + if (channel->internal.resolve_cmd_ident) { + silc_client_unref_channel(client, conn, channel); + SILC_FSM_CALL(silc_client_command_pending( + conn, SILC_COMMAND_NONE, + channel->internal.resolve_cmd_ident, + silc_client_notify_wait_continue, + fsm)); + /* NOT REACHED */ + } + /* Get the mode */ tmp = silc_argument_get_arg_type(args, 2, &tmp_len); if (!tmp) @@ -681,7 +801,9 @@ SILC_FSM_STATE(silc_client_notify_cmode_change) if (!client_entry || !client_entry->nickname[0]) { /** Resolve client */ silc_client_unref_client(client, conn, client_entry); - SILC_FSM_CALL(silc_client_get_client_by_id_resolve( + notify->channel = channel; + SILC_FSM_CALL(channel->internal.resolve_cmd_ident = + silc_client_get_client_by_id_resolve( client, conn, &id.u.client_id, NULL, silc_client_notify_resolved, fsm)); @@ -693,7 +815,9 @@ SILC_FSM_STATE(silc_client_notify_cmode_change) server = silc_client_get_server_by_id(client, conn, &id.u.server_id); if (!server) { /** Resolve server */ - SILC_FSM_CALL(silc_client_get_server_by_id_resolve( + notify->channel = channel; + SILC_FSM_CALL(channel->internal.resolve_cmd_ident = + silc_client_get_server_by_id_resolve( client, conn, &id.u.server_id, silc_client_notify_resolved, fsm)); @@ -706,7 +830,9 @@ SILC_FSM_STATE(silc_client_notify_cmode_change) &id.u.channel_id); if (!channel_entry) { /** Resolve channel */ - SILC_FSM_CALL(silc_client_get_channel_by_id_resolve( + notify->channel = channel; + SILC_FSM_CALL(channel->internal.resolve_cmd_ident = + silc_client_get_channel_by_id_resolve( client, conn, &id.u.channel_id, silc_client_notify_resolved, fsm)); @@ -800,8 +926,9 @@ SILC_FSM_STATE(silc_client_notify_cumode_change) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; + SilcPacket packet = notify->packet; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry = NULL, client_entry2 = NULL; @@ -823,6 +950,17 @@ SILC_FSM_STATE(silc_client_notify_cumode_change) if (!channel) goto out; + /* If channel is being resolved handle notify after resolving */ + if (channel->internal.resolve_cmd_ident) { + silc_client_unref_channel(client, conn, channel); + SILC_FSM_CALL(silc_client_command_pending( + conn, SILC_COMMAND_NONE, + channel->internal.resolve_cmd_ident, + silc_client_notify_wait_continue, + fsm)); + /* NOT REACHED */ + } + /* Get the mode */ tmp = silc_argument_get_arg_type(args, 2, &tmp_len); if (!tmp) @@ -839,7 +977,9 @@ SILC_FSM_STATE(silc_client_notify_cumode_change) if (!client_entry || !client_entry->nickname[0]) { /** Resolve client */ silc_client_unref_client(client, conn, client_entry); - SILC_FSM_CALL(silc_client_get_client_by_id_resolve( + notify->channel = channel; + SILC_FSM_CALL(channel->internal.resolve_cmd_ident = + silc_client_get_client_by_id_resolve( client, conn, &id.u.client_id, NULL, silc_client_notify_resolved, fsm)); @@ -851,7 +991,9 @@ SILC_FSM_STATE(silc_client_notify_cumode_change) server = silc_client_get_server_by_id(client, conn, &id.u.server_id); if (!server) { /** Resolve server */ - SILC_FSM_CALL(silc_client_get_server_by_id_resolve( + notify->channel = channel; + SILC_FSM_CALL(channel->internal.resolve_cmd_ident = + silc_client_get_server_by_id_resolve( client, conn, &id.u.server_id, silc_client_notify_resolved, fsm)); @@ -864,7 +1006,9 @@ SILC_FSM_STATE(silc_client_notify_cumode_change) &id.u.channel_id); if (!channel_entry) { /** Resolve channel */ - SILC_FSM_CALL(silc_client_get_channel_by_id_resolve( + notify->channel = channel; + SILC_FSM_CALL(channel->internal.resolve_cmd_ident = + silc_client_get_channel_by_id_resolve( client, conn, &id.u.channel_id, silc_client_notify_resolved, fsm)); @@ -921,8 +1065,8 @@ SILC_FSM_STATE(silc_client_notify_motd) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); unsigned char *tmp; @@ -952,8 +1096,8 @@ SILC_FSM_STATE(silc_client_notify_channel_change) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcChannelEntry channel = NULL; @@ -970,6 +1114,17 @@ SILC_FSM_STATE(silc_client_notify_channel_change) if (!channel) goto out; + /* If channel is being resolved handle notify after resolving */ + if (channel->internal.resolve_cmd_ident) { + silc_client_unref_channel(client, conn, channel); + SILC_FSM_CALL(silc_client_command_pending( + conn, SILC_COMMAND_NONE, + channel->internal.resolve_cmd_ident, + silc_client_notify_wait_continue, + fsm)); + /* NOT REACHED */ + } + /* Get the new ID */ if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) goto out; @@ -996,8 +1151,9 @@ SILC_FSM_STATE(silc_client_notify_kicked) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; + SilcPacket packet = notify->packet; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry, client_entry2; @@ -1009,6 +1165,25 @@ SILC_FSM_STATE(silc_client_notify_kicked) SILC_LOG_DEBUG(("Notify: KICKED")); + /* Get channel entry */ + if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL, + &id.u.channel_id, sizeof(id.u.channel_id))) + goto out; + channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id); + if (!channel) + goto out; + + /* If channel is being resolved handle notify after resolving */ + if (channel->internal.resolve_cmd_ident) { + silc_client_unref_channel(client, conn, channel); + SILC_FSM_CALL(silc_client_command_pending( + conn, SILC_COMMAND_NONE, + channel->internal.resolve_cmd_ident, + silc_client_notify_wait_continue, + fsm)); + /* NOT REACHED */ + } + /* Get Client ID */ if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL)) goto out; @@ -1018,14 +1193,6 @@ SILC_FSM_STATE(silc_client_notify_kicked) if (!client_entry) goto out; - /* Get channel entry */ - if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL, - &id.u.channel_id, sizeof(id.u.channel_id))) - goto out; - channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id); - if (!channel) - goto out; - /* Get kicker's Client ID */ if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL)) goto out; @@ -1036,7 +1203,9 @@ SILC_FSM_STATE(silc_client_notify_kicked) /** Resolve client */ silc_client_unref_client(client, conn, client_entry); silc_client_unref_client(client, conn, client_entry2); - SILC_FSM_CALL(silc_client_get_client_by_id_resolve( + notify->channel = channel; + SILC_FSM_CALL(channel->internal.resolve_cmd_ident = + silc_client_get_client_by_id_resolve( client, conn, &id.u.client_id, NULL, silc_client_notify_resolved, fsm)); @@ -1084,8 +1253,8 @@ SILC_FSM_STATE(silc_client_notify_killed) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry = NULL, client_entry2 = NULL; @@ -1185,8 +1354,8 @@ SILC_FSM_STATE(silc_client_notify_server_signoff) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry; @@ -1235,8 +1404,8 @@ SILC_FSM_STATE(silc_client_notify_error) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry; @@ -1281,12 +1450,12 @@ SILC_FSM_STATE(silc_client_notify_watch) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; - SilcPacket packet = state_context; - SilcNotifyPayload payload = (SilcNotifyPayload)packet->next; + SilcClientNotify notify = state_context; + SilcNotifyPayload payload = notify->payload; SilcNotifyType type = silc_notify_get_type(payload); SilcArgumentPayload args = silc_notify_get_args(payload); SilcClientEntry client_entry = NULL; - SilcNotifyType notify = 0; + SilcNotifyType ntype = 0; SilcBool del_client = FALSE; unsigned char *pk, *tmp; SilcUInt32 mode, pk_len, tmp_len; @@ -1322,7 +1491,7 @@ SILC_FSM_STATE(silc_client_notify_watch) if (tmp && tmp_len != 2) goto out; if (tmp) - SILC_GET16_MSB(notify, tmp); + SILC_GET16_MSB(ntype, tmp); /* Get nickname */ tmp = silc_argument_get_arg_type(args, 2, NULL); @@ -1353,7 +1522,7 @@ SILC_FSM_STATE(silc_client_notify_watch) } /* Notify application. */ - NOTIFY(client, conn, type, client_entry, tmp, mode, notify, + NOTIFY(client, conn, type, client_entry, tmp, mode, ntype, client_entry->public_key); client_entry->mode = mode; @@ -1361,12 +1530,12 @@ SILC_FSM_STATE(silc_client_notify_watch) /* If nickname was changed, remove the client entry unless the client is on some channel */ /* XXX, why do we need to remove the client entry?? */ - if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE && + if (tmp && ntype == SILC_NOTIFY_TYPE_NICK_CHANGE && !silc_hash_table_count(client_entry->channels)) del_client = TRUE; - else if (notify == SILC_NOTIFY_TYPE_SIGNOFF || - notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF || - notify == SILC_NOTIFY_TYPE_KILLED) + else if (ntype == SILC_NOTIFY_TYPE_SIGNOFF || + ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF || + ntype == SILC_NOTIFY_TYPE_KILLED) del_client = TRUE; if (del_client) diff --git a/lib/silcclient/client_prvmsg.c b/lib/silcclient/client_prvmsg.c index a932fbf7..61c43b62 100644 --- a/lib/silcclient/client_prvmsg.c +++ b/lib/silcclient/client_prvmsg.c @@ -484,7 +484,7 @@ SilcBool silc_client_add_private_message_key(SilcClient client, /* Produce the key material as the protocol defines */ keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16, - client->sha1hash); + conn->internal->sha1hash); if (!keymat) return FALSE; diff --git a/lib/silcclient/client_register.c b/lib/silcclient/client_register.c index 98a86f51..5d12f79b 100644 --- a/lib/silcclient/client_register.c +++ b/lib/silcclient/client_register.c @@ -23,6 +23,19 @@ /************************** Types and definitions ***************************/ +/* Resume session context */ +typedef struct { + SilcClient client; + SilcClientConnection conn; + SilcBufferStruct detach; + char *nickname; + SilcClientID client_id; + SilcUInt32 channel_count; + SilcUInt32 *cmd_idents; + SilcUInt32 cmd_idents_count; + SilcBool success; +} *SilcClientResumeSession; + /************************ Static utility functions **************************/ @@ -49,9 +62,7 @@ SILC_FSM_STATE(silc_client_new_id) /* Create local client entry */ conn->local_entry = silc_client_add_client(client, conn, - (client->nickname ? - client->nickname : - client->username), + client->username, client->username, client->realname, &id.u.client_id, 0); @@ -60,7 +71,7 @@ SILC_FSM_STATE(silc_client_new_id) /* Save the ID */ conn->local_id = &conn->local_entry->id; - conn->local_idp = silc_buffer_copy(&packet->buffer); + conn->internal->local_idp = silc_buffer_copy(&packet->buffer); /* Save cache entry */ silc_idcache_find_by_id_one(conn->internal->client_cache, conn->local_id, @@ -68,13 +79,14 @@ SILC_FSM_STATE(silc_client_new_id) /* Save remote ID */ if (packet->src_id_len) { - conn->remote_idp = silc_id_payload_encode_data(packet->src_id, - packet->src_id_len, - packet->src_id_type); - if (!conn->remote_idp) + conn->internal->remote_idp = + silc_id_payload_encode_data(packet->src_id, + packet->src_id_len, + packet->src_id_type); + if (!conn->internal->remote_idp) goto out; - silc_id_payload_parse_id(silc_buffer_data(conn->remote_idp), - silc_buffer_len(conn->remote_idp), + silc_id_payload_parse_id(silc_buffer_data(conn->internal->remote_idp), + silc_buffer_len(conn->internal->remote_idp), &conn->remote_id); } @@ -129,7 +141,7 @@ SILC_FSM_STATE(silc_client_st_register_complete) SilcClient client = conn->client; if (!conn->local_id) { - /* Timeout, ID not received */ + /** Timeout, ID not received */ conn->internal->registering = FALSE; silc_fsm_next(fsm, silc_client_st_register_error); return SILC_FSM_CONTINUE; @@ -140,25 +152,26 @@ SILC_FSM_STATE(silc_client_st_register_complete) /* Issue IDENTIFY command for itself to get resolved hostname correctly from server. */ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, NULL, NULL, - 1, 5, silc_buffer_data(conn->local_idp), - silc_buffer_len(conn->local_idp)); + 1, 5, silc_buffer_data(conn->internal->local_idp), + silc_buffer_len(conn->internal->local_idp)); /* Send NICK command if the nickname was set by the application (and is not same as the username). Send this with little timeout. */ - if (client->nickname && - !silc_utf8_strcasecmp(client->nickname, client->username)) + if (conn->internal->params.nickname && + !silc_utf8_strcasecmp(conn->internal->params.nickname, client->username)) silc_client_command_send(client, conn, SILC_COMMAND_NICK, NULL, NULL, - 1, 1, client->nickname, strlen(client->nickname)); + 1, 1, conn->internal->params.nickname, + strlen(conn->internal->params.nickname)); /* Issue INFO command to fetch the real server name and server information and other stuff. */ silc_client_command_send(client, conn, SILC_COMMAND_INFO, NULL, NULL, - 1, 2, silc_buffer_data(conn->remote_idp), - silc_buffer_len(conn->remote_idp)); + 1, 2, silc_buffer_data(conn->internal->remote_idp), + silc_buffer_len(conn->internal->remote_idp)); /* Call connection callback. We are now inside SILC network. */ conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL, - conn->context); + conn->callback_context); conn->internal->registering = FALSE; return SILC_FSM_FINISH; @@ -172,7 +185,8 @@ SILC_FSM_STATE(silc_client_st_register_error) /* XXX */ /* Close connection */ - conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL, conn->context); + conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL, + conn->callback_context); return SILC_FSM_FINISH; } @@ -184,13 +198,128 @@ SILC_FSM_STATE(silc_client_st_register_error) SILC_FSM_STATE(silc_client_st_resume) { + SilcClientConnection conn = fsm_context; + SilcClient client = conn->client; + SilcClientResumeSession resume; + SilcBuffer auth; + unsigned char *id; + SilcUInt16 id_len; + int ret; + + SILC_LOG_DEBUG(("Resuming detached session")); + + resume = silc_calloc(1, sizeof(*resume)); + if (!resume) { + /** Out of memory */ + silc_fsm_next(fsm, silc_client_st_resume_error); + return SILC_FSM_CONTINUE; + } + silc_fsm_set_state_context(fsm, resume); + + silc_buffer_set(&resume->detach, conn->internal->params.detach_data, + conn->internal->params.detach_data_len); + SILC_LOG_HEXDUMP(("Detach data"), silc_buffer_data(&resume->detach), + silc_buffer_len(&resume->detach)); + + /* Take the old client ID from the detachment data */ + ret = silc_buffer_unformat(&resume->detach, + SILC_STR_ADVANCE, + SILC_STR_UI16_NSTRING_ALLOC(&resume->nickname, + NULL), + SILC_STR_UI16_NSTRING(&id, &id_len), + SILC_STR_UI_INT(NULL), + SILC_STR_UI_INT(&resume->channel_count), + SILC_STR_END); + if (ret < 0) { + /** Malformed detach data */ + silc_fsm_next(fsm, silc_client_st_resume_error); + return SILC_FSM_CONTINUE; + } - return SILC_FSM_FINISH; + if (!silc_id_str2id(id, id_len, SILC_ID_CLIENT, &resume->client_id, + sizeof(resume->client_id))) { + /** Malformed ID */ + silc_fsm_next(fsm, silc_client_st_resume_error); + return SILC_FSM_CONTINUE; + } + + /* Generate authentication data that server will verify */ + auth = silc_auth_public_key_auth_generate(conn->public_key, + conn->private_key, + client->rng, + conn->internal->hash, + &resume->client_id, + SILC_ID_CLIENT); + if (!auth) { + /** Out of memory */ + silc_fsm_next(fsm, silc_client_st_resume_error); + return SILC_FSM_CONTINUE; + } + + /* Send RESUME_CLIENT packet to resume to network */ + if (!silc_packet_send_va(conn->stream, SILC_PACKET_RESUME_CLIENT, 0, + SILC_STR_UI_SHORT(id_len), + SILC_STR_UI_XNSTRING(id, id_len), + SILC_STR_UI_XNSTRING(silc_buffer_data(auth), + silc_buffer_len(auth)), + SILC_STR_END)) { + /** Error sending packet */ + silc_fsm_next(fsm, silc_client_st_resume_error); + return SILC_FSM_CONTINUE; + } + + /** Wait for new ID */ + conn->internal->registering = TRUE; + silc_fsm_next_later(fsm, silc_client_st_resume_resolve, 15, 0); + return SILC_FSM_WAIT; } -SILC_FSM_STATE(silc_client_st_resume_new_id) +/* Resolve the old session information */ + +SILC_FSM_STATE(silc_client_st_resume_resolve) { +#if 0 SilcClientConnection conn = fsm_context; + SilcClientResumeSession resume = state_context; + + if (!conn->local_id) { + /** Timeout, ID not received */ + conn->internal->registering = FALSE; + silc_fsm_next(fsm, silc_client_st_resume_error); + return SILC_FSM_CONTINUE; + } + + + for (i = 0; i < ch_count; i++) { + char *channel; + unsigned char *chid; + SilcUInt16 chid_len; + SilcUInt32 ch_mode; + SilcChannelID *channel_id; + SilcChannelEntry channel_entry; + + len = silc_buffer_unformat(&detach, + SILC_STR_UI16_NSTRING_ALLOC(&channel, NULL), + SILC_STR_UI16_NSTRING(&chid, &chid_len), + SILC_STR_UI_INT(&ch_mode), + SILC_STR_END); + if (len == -1) + return FALSE; + + /* Add new channel */ + channel_id = silc_id_str2id(chid, chid_len, SILC_ID_CHANNEL); + channel_entry = silc_client_get_channel_by_id(client, conn, channel_id); + if (!channel_entry) { + channel_entry = silc_client_add_channel(client, conn, channel, ch_mode, + channel_id); + } else { + silc_free(channel); + silc_free(channel_id); + } + + silc_buffer_pull(&detach, len); + } +#endif /* 0 */ return SILC_FSM_FINISH; } @@ -202,3 +331,70 @@ SILC_FSM_STATE(silc_client_st_resume_error) return SILC_FSM_FINISH; } + +/* Generates the session detachment data. This data can be used later + to resume back to the server. */ + +SilcBuffer silc_client_get_detach_data(SilcClient client, + SilcClientConnection conn) +{ + SilcBuffer detach; + SilcHashTableList htl; + SilcChannelUser chu; + int ret, ch_count; + + SILC_LOG_DEBUG(("Creating detachment data")); + + ch_count = silc_hash_table_count(conn->local_entry->channels); + + /* Save the nickname, Client ID and user mode in SILC network */ + detach = silc_buffer_alloc(0); + if (!detach) + return NULL; + ret = + silc_buffer_format(detach, + SILC_STR_ADVANCE, + SILC_STR_UI_SHORT(strlen(conn->local_entry->nickname)), + SILC_STR_DATA(conn->local_entry->nickname, + strlen(conn->local_entry->nickname)), + SILC_STR_UI_SHORT(silc_buffer_len(conn->internal-> + local_idp)), + SILC_STR_DATA(silc_buffer_data(conn->internal-> + local_idp), + silc_buffer_len(conn->internal-> + local_idp)), + SILC_STR_UI_INT(conn->local_entry->mode), + SILC_STR_UI_INT(ch_count), + SILC_STR_END); + if (ret < 0) { + silc_buffer_free(detach); + return NULL; + } + + /* Save all joined channels */ + silc_hash_table_list(conn->local_entry->channels, &htl); + while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { + unsigned char chid[32]; + SilcUInt32 chid_len; + + silc_id_id2str(&chu->channel->id, SILC_ID_CHANNEL, chid, sizeof(chid), + &chid_len); + silc_buffer_format(detach, + SILC_STR_ADVANCE, + SILC_STR_UI_SHORT(strlen(chu->channel->channel_name)), + SILC_STR_DATA(chu->channel->channel_name, + strlen(chu->channel->channel_name)), + SILC_STR_UI_SHORT(chid_len), + SILC_STR_DATA(chid, chid_len), + SILC_STR_UI_INT(chu->channel->mode), + SILC_STR_END); + silc_free(chid); + } + silc_hash_table_list_reset(&htl); + + silc_buffer_start(detach); + SILC_LOG_HEXDUMP(("Detach data"), silc_buffer_data(detach), + silc_buffer_len(detach)); + + return detach; +} diff --git a/lib/silcclient/client_register.h b/lib/silcclient/client_register.h index 0aff00a6..9343da97 100644 --- a/lib/silcclient/client_register.h +++ b/lib/silcclient/client_register.h @@ -25,7 +25,10 @@ SILC_FSM_STATE(silc_client_st_register); SILC_FSM_STATE(silc_client_st_register_complete); SILC_FSM_STATE(silc_client_st_register_error); SILC_FSM_STATE(silc_client_st_resume); -SILC_FSM_STATE(silc_client_st_resume_new_id); +SILC_FSM_STATE(silc_client_st_resume_resolve); SILC_FSM_STATE(silc_client_st_resume_error); +SilcBuffer silc_client_get_detach_data(SilcClient client, + SilcClientConnection conn); + #endif /* CLIENT_REGISTER_H */ diff --git a/lib/silcclient/client_resume.c b/lib/silcclient/client_resume.c index 5b984234..dbad9c79 100644 --- a/lib/silcclient/client_resume.c +++ b/lib/silcclient/client_resume.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2002, 2004 Pekka Riikonen + Copyright (C) 2002, 2004, 2006 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -36,157 +36,6 @@ do { \ 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); \ } while(0) -/* Generates the session detachment data. This data can be used later - to resume back to the server. */ - -SilcBuffer silc_client_get_detach_data(SilcClient client, - SilcClientConnection conn) -{ - SilcBuffer detach; - SilcHashTableList htl; - SilcChannelUser chu; - int ch_count; - - SILC_LOG_DEBUG(("Creating detachment data")); - - ch_count = silc_hash_table_count(conn->local_entry->channels); - - /* Save the nickname, Client ID and user mode in SILC network */ - detach = silc_buffer_alloc_size(2 + strlen(conn->nickname) + - 2 + conn->local_id_data_len + 4 + 4); - silc_buffer_format(detach, - SILC_STR_UI_SHORT(strlen(conn->nickname)), - SILC_STR_UI_XNSTRING(conn->nickname, - strlen(conn->nickname)), - SILC_STR_UI_SHORT(conn->local_id_data_len), - SILC_STR_UI_XNSTRING(conn->local_id_data, - conn->local_id_data_len), - SILC_STR_UI_INT(conn->local_entry->mode), - SILC_STR_UI_INT(ch_count), - SILC_STR_END); - - /* Save all joined channels */ - silc_hash_table_list(conn->local_entry->channels, &htl); - while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { - unsigned char *chid = silc_id_id2str(chu->channel->id, SILC_ID_CHANNEL); - SilcUInt16 chid_len = silc_id_get_len(chu->channel->id, SILC_ID_CHANNEL); - - detach = silc_buffer_realloc(detach, detach->truelen + 2 + - strlen(chu->channel->channel_name) + - 2 + chid_len + 4); - silc_buffer_pull(detach, detach->len); - silc_buffer_pull_tail(detach, 2 + strlen(chu->channel->channel_name) + - 2 + chid_len + 4); - silc_buffer_format(detach, - SILC_STR_UI_SHORT(strlen(chu->channel->channel_name)), - SILC_STR_UI_XNSTRING(chu->channel->channel_name, - strlen(chu->channel->channel_name)), - SILC_STR_UI_SHORT(chid_len), - SILC_STR_UI_XNSTRING(chid, chid_len), - SILC_STR_UI_INT(chu->channel->mode), - SILC_STR_END); - silc_free(chid); - } - silc_hash_table_list_reset(&htl); - - silc_buffer_push(detach, detach->data - detach->head); - - SILC_LOG_HEXDUMP(("Detach data"), detach->data, detach->len); - - return detach; -} - -/* Processes the detachment data. This creates channels and other - stuff according the data found in the the connection parameters. - This doesn't actually resolve any detailed information from the - server. To do that call silc_client_resume_session function. - This returns the old detached session client ID. */ - -SilcBool silc_client_process_detach_data(SilcClient client, - SilcClientConnection conn, - unsigned char **old_id, - SilcUInt16 *old_id_len) -{ - SilcBufferStruct detach; - SilcUInt32 ch_count; - int i, len; - char *newnick; - - SILC_LOG_DEBUG(("Start")); - - silc_buffer_set(&detach, conn->internal->params.detach_data, - conn->internal->params.detach_data_len); - - SILC_LOG_HEXDUMP(("Detach data"), detach.data, detach.len); - - *old_id = NULL; - *old_id_len = 0; - - /* Take the old client ID from the detachment data */ - len = silc_buffer_unformat(&detach, - SILC_STR_UI16_NSTRING_ALLOC(&newnick, - NULL), - SILC_STR_UI16_NSTRING_ALLOC(old_id, old_id_len), - SILC_STR_UI_INT(NULL), - SILC_STR_UI_INT(&ch_count), - SILC_STR_END); - if (len == -1) - return FALSE; - if (!newnick || !(*old_id) || !(*old_id_len)) - return FALSE; - - silc_free(conn->nickname); - conn->nickname = newnick; - - silc_buffer_pull(&detach, len); - - for (i = 0; i < ch_count; i++) { - char *channel; - unsigned char *chid; - SilcUInt16 chid_len; - SilcUInt32 ch_mode; - SilcChannelID *channel_id; - SilcChannelEntry channel_entry; - - len = silc_buffer_unformat(&detach, - SILC_STR_UI16_NSTRING_ALLOC(&channel, NULL), - SILC_STR_UI16_NSTRING(&chid, &chid_len), - SILC_STR_UI_INT(&ch_mode), - SILC_STR_END); - if (len == -1) - return FALSE; - - /* Add new channel */ - channel_id = silc_id_str2id(chid, chid_len, SILC_ID_CHANNEL); - channel_entry = silc_client_get_channel_by_id(client, conn, channel_id); - if (!channel_entry) { - channel_entry = silc_client_add_channel(client, conn, channel, ch_mode, - channel_id); - } else { - silc_free(channel); - silc_free(channel_id); - } - - silc_buffer_pull(&detach, len); - } - silc_buffer_push(&detach, detach.data - detach.head); - - return TRUE; -} - - -/* Resume session context */ -typedef struct { - SilcClient client; - SilcClientConnection conn; - SilcClientResumeSessionCallback callback; - void *context; - SilcUInt32 channel_count; - SilcUInt32 *cmd_idents; - SilcUInt32 cmd_idents_count; - SilcBool success; -} *SilcClientResumeSession; - /* Generic command reply callback. */ SILC_CLIENT_CMD_REPLY_FUNC(resume) diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index 68e9eed6..0eed6981 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -589,8 +589,8 @@ SILC_FSM_STATE(silc_client_command_whois) /* Given without arguments fetches client's own information */ if (cmd->argc < 2) { silc_client_command_send(conn->client, conn, SILC_COMMAND_WHOIS, - NULL, NULL, 1, - 4, silc_buffer_datalen(conn->local_idp)); + NULL, NULL, 1, 4, + silc_buffer_datalen(conn->internal->local_idp)); goto out; } @@ -1054,7 +1054,7 @@ SILC_FSM_STATE(silc_client_command_quit_final) /* Call connection callback */ conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED, - 0, NULL, conn->context); + 0, NULL, conn->callback_context); /* Signal to close connection */ conn->internal->disconnected = TRUE; @@ -1137,7 +1137,7 @@ SILC_FSM_STATE(silc_client_command_kill) auth = silc_auth_public_key_auth_generate(conn->public_key, conn->private_key, conn->client->rng, - client->sha1hash, + conn->internal->sha1hash, &target->id, SILC_ID_CLIENT); } } @@ -1202,7 +1202,8 @@ SILC_FSM_STATE(silc_client_command_stats) /* Send the command */ silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1, - 1, silc_buffer_datalen(conn->remote_idp)); + 1, silc_buffer_datalen(conn->internal-> + remote_idp)); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -1228,7 +1229,8 @@ SILC_FSM_STATE(silc_client_command_ping) /* Send the command */ silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 1, - 1, silc_buffer_datalen(conn->remote_idp)); + 1, silc_buffer_datalen(conn->internal-> + remote_idp)); /* Save ping time */ cmd->context = SILC_64_TO_PTR(silc_time()); @@ -1278,7 +1280,7 @@ SILC_FSM_STATE(silc_client_command_join) auth = silc_auth_public_key_auth_generate(conn->public_key, conn->private_key, conn->client->rng, - conn->client->sha1hash, + conn->internal->sha1hash, conn->local_id, SILC_ID_CLIENT); } else if (!strcasecmp(cmd->argv[i], "-auth")) { @@ -1304,13 +1306,13 @@ SILC_FSM_STATE(silc_client_command_join) } pk = silc_pkcs_public_key_encode(pubkey, &pk_len); - silc_hash_make(conn->client->sha1hash, pk, pk_len, pkhash); + silc_hash_make(conn->internal->sha1hash, pk, pk_len, pkhash); silc_free(pk); pubdata = silc_rng_get_rn_data(conn->client->rng, 128); memcpy(pubdata, pkhash, 20); cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey, pubdata, 128, - conn->client->sha1hash, + conn->internal->sha1hash, conn->local_id, SILC_ID_CLIENT); memset(pubdata, 0, 128); @@ -1334,7 +1336,8 @@ SILC_FSM_STATE(silc_client_command_join) /* Send JOIN command to the server */ silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 7, 1, name, strlen(name), - 2, silc_buffer_datalen(conn->local_idp), + 2, silc_buffer_datalen(conn->internal-> + local_idp), 3, passphrase, passphrase_len, 4, cipher, cipher ? strlen(cipher) : 0, 5, hmac, hmac ? strlen(hmac) : 0, @@ -1519,7 +1522,8 @@ SILC_FSM_STATE(silc_client_command_umode) /* Send the command */ silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2, - 1, silc_buffer_datalen(conn->local_idp), + 1, silc_buffer_datalen(conn->internal-> + local_idp), 2, modebuf, sizeof(modebuf)); /* Notify application */ @@ -1720,7 +1724,7 @@ SILC_FSM_STATE(silc_client_command_cmode) pk = silc_public_key_payload_encode(pubkey); auth = silc_auth_public_key_auth_generate(pubkey, privkey, conn->client->rng, - conn->client->sha1hash, + conn->internal->sha1hash, conn->local_id, SILC_ID_CLIENT); arg = silc_buffer_data(auth); @@ -1933,7 +1937,7 @@ SILC_FSM_STATE(silc_client_command_cumode) auth = silc_auth_public_key_auth_generate(pubkey, privkey, conn->client->rng, - conn->client->sha1hash, + conn->internal->sha1hash, conn->local_id, SILC_ID_CLIENT); mode |= SILC_CHANNEL_UMODE_CHANFO; @@ -2392,7 +2396,8 @@ SILC_FSM_STATE(silc_client_command_watch) /* Send the commmand */ silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, 2, - 1, silc_buffer_datalen(conn->local_idp), + 1, silc_buffer_datalen(conn->internal-> + local_idp), type, pubkey ? args->data : cmd->argv[2], pubkey ? silc_buffer_len(args) : cmd->argv_lens[2]); diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index dd4c2f1a..bc7b20fd 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -670,8 +670,8 @@ SILC_FSM_STATE(silc_client_command_reply_nick) } memcpy(conn->local_entry->nickname, nick, strlen(nick)); conn->local_entry->nickname_normalized = tmp; - silc_buffer_enlarge(conn->local_idp, idp_len); - silc_buffer_put(conn->local_idp, idp, idp_len); + silc_buffer_enlarge(conn->internal->local_idp, idp_len); + silc_buffer_put(conn->internal->local_idp, idp, idp_len); silc_client_nickname_format(client, conn, conn->local_entry); /* Notify application */ @@ -805,7 +805,7 @@ SILC_FSM_STATE(silc_client_command_reply_invite) SilcChannelEntry channel; unsigned char *tmp; SilcUInt32 len; - SilcBufferStruct buf; + SilcArgumentPayload invite_args = NULL; SilcID id; /* Sanity checks */ @@ -828,10 +828,13 @@ SILC_FSM_STATE(silc_client_command_reply_invite) /* Get the invite list */ tmp = silc_argument_get_arg_type(args, 3, &len); if (tmp) - silc_buffer_set(&buf, tmp, len); + invite_args = silc_argument_list_parse(tmp, len); /* Notify application */ - silc_client_command_callback(cmd, channel, tmp ? &buf : NULL); + silc_client_command_callback(cmd, channel, invite_args); + + if (invite_args) + silc_argument_payload_free(invite_args); out: silc_fsm_next(fsm, silc_client_command_reply_processed); @@ -1019,6 +1022,25 @@ SILC_FSM_STATE(silc_client_command_reply_ping) /********************************** JOIN ************************************/ +/* Continue JOIN command reply processing after resolving unknown users */ + +static void +silc_client_command_reply_join_resolved(SilcClient client, + SilcClientConnection conn, + SilcStatus status, + SilcDList clients, + void *context) +{ + SilcClientCommandContext cmd = context; + SilcChannelEntry channel = cmd->context; + + channel->internal.resolve_cmd_ident = 0; + silc_client_unref_channel(client, conn, channel); + + SILC_FSM_CALL_CONTINUE(&cmd->thread); +} + + /* Received reply for JOIN command. */ SILC_FSM_STATE(silc_client_command_reply_join) @@ -1031,8 +1053,10 @@ SILC_FSM_STATE(silc_client_command_reply_join) SilcChannelEntry channel; SilcUInt32 mode = 0, len, list_count; char *topic, *tmp, *channel_name = NULL, *hmac; - SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL; - SilcBufferStruct chpklist; + const char *cipher; + SilcBufferStruct client_id_list, client_mode_list, keyp; + SilcHashTableList htl; + SilcDList chpks = NULL; SilcID id; int i; @@ -1053,22 +1077,6 @@ SILC_FSM_STATE(silc_client_command_reply_join) goto out; } - /* Get channel mode */ - tmp = silc_argument_get_arg_type(args, 5, NULL); - if (tmp) - SILC_GET32_MSB(mode, tmp); - - /* Get channel key */ - tmp = silc_argument_get_arg_type(args, 7, &len); - if (tmp) { - keyp = silc_buffer_alloc_size(len); - if (keyp) - silc_buffer_put(keyp, tmp, len); - } - - /* Get topic */ - topic = silc_argument_get_arg_type(args, 10, NULL); - /* Check whether we have this channel entry already. */ channel = silc_client_get_channel(client, conn, channel_name); if (channel) { @@ -1082,21 +1090,7 @@ SILC_FSM_STATE(silc_client_command_reply_join) ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL); goto out; } - } - - conn->current_channel = channel; - channel->mode = mode; - - /* Get hmac */ - hmac = silc_argument_get_arg_type(args, 11, NULL); - if (hmac) { - if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) { - if (cmd->verbose) - SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR, - "Cannot join channel: Unsupported HMAC `%s'", hmac); - ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM); - goto out; - } + silc_client_ref_channel(client, conn, channel); } /* Get the list count */ @@ -1113,10 +1107,18 @@ SILC_FSM_STATE(silc_client_command_reply_join) ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } + silc_buffer_set(&client_id_list, tmp, len); - client_id_list = silc_buffer_alloc_size(len); - if (client_id_list) - silc_buffer_put(client_id_list, tmp, len); + /* Resolve users we do not know about */ + if (!cmd->resolved) { + cmd->resolved = TRUE; + cmd->context = channel; + SILC_FSM_CALL(channel->internal.resolve_cmd_ident = + silc_client_get_clients_by_list( + client, conn, list_count, &client_id_list, + silc_client_command_reply_join_resolved, cmd)); + /* NOT REACHED */ + } /* Get client mode list */ tmp = silc_argument_get_arg_type(args, 14, &len); @@ -1124,10 +1126,7 @@ SILC_FSM_STATE(silc_client_command_reply_join) ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } - - client_mode_list = silc_buffer_alloc_size(len); - if (client_mode_list) - silc_buffer_put(client_mode_list, tmp, len); + silc_buffer_set(&client_mode_list, tmp, len); /* Add clients we received in the reply to the channel */ for (i = 0; i < list_count; i++) { @@ -1137,45 +1136,60 @@ SILC_FSM_STATE(silc_client_command_reply_join) SilcClientEntry client_entry; /* Client ID */ - SILC_GET16_MSB(idp_len, client_id_list->data + 2); + SILC_GET16_MSB(idp_len, client_id_list.data + 2); idp_len += 4; - if (!silc_id_payload_parse_id(client_id_list->data, idp_len, &id)) - goto out; + if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id)) + continue; /* Mode */ - SILC_GET32_MSB(mode, client_mode_list->data); + SILC_GET32_MSB(mode, client_mode_list.data); - /* Check if we have this client cached already. */ + /* Get client entry */ client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id); - if (!client_entry) { - /* No, we don't have it, add entry for it. */ - client_entry = - silc_client_add_client(client, conn, NULL, NULL, NULL, - &id.u.client_id, 0); - if (!client_entry) - goto out; - } + if (!client_entry) + continue; /* Join client to the channel */ - if (!silc_client_add_to_channel(channel, client_entry, mode)) { - silc_client_unref_client(client, conn, client_entry); - goto out; - } + silc_client_add_to_channel(channel, client_entry, mode); silc_client_unref_client(client, conn, client_entry); - if (!silc_buffer_pull(client_id_list, idp_len)) + if (!silc_buffer_pull(&client_id_list, idp_len)) goto out; - if (!silc_buffer_pull(client_mode_list, 4)) + if (!silc_buffer_pull(&client_mode_list, 4)) goto out; } - silc_buffer_start(client_id_list); - silc_buffer_start(client_mode_list); - /* Save channel key */ -#if 0 - if (keyp) - silc_client_save_channel_key(client, conn, keyp, channel); -#endif /* 0 */ + /* Get hmac */ + hmac = silc_argument_get_arg_type(args, 11, NULL); + if (hmac) { + if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) { + if (cmd->verbose) + SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR, + "Cannot join channel: Unsupported HMAC `%s'", hmac); + ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM); + goto out; + } + } + + /* Get channel mode */ + tmp = silc_argument_get_arg_type(args, 5, NULL); + if (tmp) + SILC_GET32_MSB(mode, tmp); + channel->mode = mode; + + /* Get channel key and save it */ + tmp = silc_argument_get_arg_type(args, 7, &len); + if (tmp) { + silc_buffer_set(&keyp, tmp, len); + silc_client_save_channel_key(client, conn, &keyp, channel); + } + + /* Get topic */ + topic = silc_argument_get_arg_type(args, 10, NULL); + if (topic) { + silc_free(channel->topic); + channel->topic = silc_memdup(topic, strlen(topic)); + } /* Get founder key */ tmp = silc_argument_get_arg_type(args, 15, &len); @@ -1196,24 +1210,27 @@ SILC_FSM_STATE(silc_client_command_reply_join) /* Get channel public key list */ tmp = silc_argument_get_arg_type(args, 16, &len); if (tmp) - silc_buffer_set(&chpklist, tmp, len); + chpks = silc_argument_list_parse_decoded(tmp, len, + SILC_ARGUMENT_PUBLIC_KEY); - if (topic) { - silc_free(channel->topic); - channel->topic = silc_memdup(topic, strlen(topic)); - } + /* Set current channel */ + conn->current_channel = channel; + + cipher = (channel->internal.channel_key ? + silc_cipher_get_name(channel->internal.channel_key) : NULL); + silc_hash_table_list(channel->user_list, &htl); /* Notify application */ - silc_client_command_callback(cmd, channel_name, channel, mode, 0, - keyp ? keyp->head : NULL, NULL, - NULL, topic, hmac, list_count, client_id_list, - client_mode_list, channel->founder_key, - tmp ? &chpklist : NULL, channel->user_limit); + silc_client_command_callback(cmd, channel_name, channel, mode, &htl, + topic, cipher, hmac, channel->founder_key, + chpks, channel->user_limit); + + if (chpks) + silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY); + silc_hash_table_list_reset(&htl); + silc_client_unref_channel(client, conn, channel); out: - silc_buffer_free(keyp); - silc_buffer_free(client_id_list); - silc_buffer_free(client_mode_list); silc_fsm_next(fsm, silc_client_command_reply_processed); return SILC_FSM_CONTINUE; } @@ -1610,7 +1627,7 @@ SILC_FSM_STATE(silc_client_command_reply_ban) SilcChannelEntry channel; unsigned char *tmp; SilcUInt32 len; - SilcBufferStruct buf; + SilcArgumentPayload invite_args = NULL; SilcID id; /* Sanity checks */ @@ -1630,13 +1647,16 @@ SILC_FSM_STATE(silc_client_command_reply_ban) goto out; } - /* Get the ban list */ + /* Get the invite list */ tmp = silc_argument_get_arg_type(args, 3, &len); if (tmp) - silc_buffer_set(&buf, tmp, len); + invite_args = silc_argument_list_parse(tmp, len); /* Notify application */ - silc_client_command_callback(cmd, channel, tmp ? &buf : NULL); + silc_client_command_callback(cmd, channel, invite_args); + + if (invite_args) + silc_argument_payload_free(invite_args); out: silc_fsm_next(fsm, silc_client_command_reply_processed); @@ -1690,7 +1710,7 @@ SILC_FSM_STATE(silc_client_command_reply_leave) /********************************* USERS ************************************/ -/* Continue USERS command after resolving unknown users */ +/* Continue USERS command reply processing after resolving unknown users */ static void silc_client_command_reply_users_resolved(SilcClient client, @@ -1703,6 +1723,7 @@ silc_client_command_reply_users_resolved(SilcClient client, SILC_FSM_CALL_CONTINUE(&cmd->thread); } + /* Continue USERS command after resolving unknown channel */ static void @@ -1884,7 +1905,7 @@ SILC_FSM_STATE(silc_client_command_reply_getkey) /* Save fingerprint */ if (!client_entry->fingerprint) - silc_hash_make(client->sha1hash, tmp + 4, len - 4, + silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4, client_entry->fingerprint); if (!client_entry->public_key) { client_entry->public_key = public_key; diff --git a/lib/silcclient/silcclient.h b/lib/silcclient/silcclient.h index 254241ff..bb7bc9aa 100644 --- a/lib/silcclient/silcclient.h +++ b/lib/silcclient/silcclient.h @@ -130,41 +130,21 @@ typedef void (*SilcClientConnectCallback)(SilcClient client, * is initialized with silc_client_init function, and freed with * silc_client_free function. * + * This context represents the client. Each connection to remote server + * is represented by SilcClientConnection context. + * * SOURCE */ struct SilcClientStruct { - /* - * The following fields are set by application. Strings MUST be UTF-8 - * encoded strings. - */ - char *nickname; /* Nickname, MAY be set by application */ - char *username; /* Username, MUST be set by application */ - char *hostname; /* hostname, MUST be set by application */ - char *realname; /* Real name, MUST be set be application */ - - /* - * The following fields are set by the library - */ - - /* Scheduler, set by library. Application may use this pointer. */ - SilcSchedule schedule; - - /* Random Number Generator. Application should use this as its primary - random number generator. */ - SilcRng rng; - - /* Application specific user data pointer. Client library does not - touch this. This the context sent as argument to silc_client_alloc. - Application can use it freely. */ - void *application; - - /* Generic hash context for application usage */ - /* XXX remove these; not thread safe */ - SilcHash md5hash; - SilcHash sha1hash; - - /* Internal data for client library. Application cannot access this - data at all. */ + char *username; /* Username */ + char *hostname; /* hostname */ + char *realname; /* Real name */ + SilcSchedule schedule; /* Client scheduler */ + SilcRng rng; /* Random number generator */ + void *application; /* Application specific context, set with + silc_client_alloc. */ + + /* Internal data for client library. Application cannot access this. */ SilcClientInternal internal; }; /***/ @@ -178,33 +158,21 @@ struct SilcClientStruct { * * DESCRIPTION * - * This structure represents a connection. When connection is created - * to server this is context is returned to the application in the - * "connected" client operation. It includes all the important - * data for the session, such as nickname, local and remote IDs, and - * other information. All strings in the structure are UTF-8 encoded. + * This structure represents a connection. It is allocated and freed by + * the library. It is returned to application in SilcClientConnectCallback. + * It includes all the important data for the session such as local + * client entry (which includes current nickname), local and remote IDs, + * and other information. All strings in the structure are UTF-8 encoded. * * SOURCE */ struct SilcClientConnectionStruct { - /* - * Local data - */ - SilcClientEntry local_entry; /* Own Client Entry */ - SilcClientID *local_id; /* Current Client ID */ - SilcBuffer local_idp; /* Current Client ID Payload */ - - /* - * Remote data - */ - char *remote_host; /* Remote host name, UTF-8 encoded */ + SilcClientEntry local_entry; /* Our own Client Entry */ + SilcClientID *local_id; /* Our current Client ID */ + + char *remote_host; /* Remote host name */ int remote_port; /* Remote port */ SilcID remote_id; /* Remote ID */ - SilcBuffer remote_idp; /* Remote ID Payload */ - - /* - * Common data - */ SilcChannelEntry current_channel; /* Current joined channel */ SilcPublicKey public_key; /* Public key used in this connection */ @@ -212,9 +180,12 @@ struct SilcClientConnectionStruct { SilcPacketStream stream; /* Connection to remote host */ SilcConnectionType type; /* Connection type */ SilcClientConnectCallback callback; /* Connection callback */ - void *context; /* Connection context */ + void *callback_context; /* Connection context */ SilcClient client; /* Pointer back to SilcClient */ + /* Application specific data. Application may set here whatever it wants. */ + void *context; + /* Internal data for client library. Application cannot access this. */ SilcClientConnectionInternal internal; }; @@ -673,9 +644,8 @@ typedef struct { SilcBool threads; /* Number of maximum tasks the client library's scheduler can handle. - If set to zero, the default value will be used (200). For WIN32 - systems this should be set to 64 as it is the hard limit dictated - by the WIN32. */ + If set to zero default value will be used. For WIN32 systems this + should be set to 64 as it is the hard limit dictated by the WIN32. */ int task_max; /* Rekey timeout in seconds. The client will perform rekey in this @@ -801,7 +771,8 @@ void silc_client_free(SilcClient client); * * SYNOPSIS * - * SilcBool silc_client_init(SilcClient client); + * SilcBool silc_client_init(SilcClient client, const char *username, + * const char *hostname, const char *realname); * * DESCRIPTION * @@ -809,8 +780,14 @@ void silc_client_free(SilcClient client); * the client ready to be run. One must call silc_client_run to run the * client. Returns FALSE if error occurred, TRUE otherwise. * + * The `username', `hostname' and `realname' strings must be given and + * they must be UTF-8 encoded. The `username' is the client's username + * in the operating system, `hostname' is the client's host name and + * the `realname' is the user's real name. + * ***/ -SilcBool silc_client_init(SilcClient client); +SilcBool silc_client_init(SilcClient client, const char *username, + const char *hostname, const char *realname); /****f* silcclient/SilcClientAPI/silc_client_run * @@ -879,6 +856,13 @@ void silc_client_stop(SilcClient client); * SOURCE */ typedef struct { + /* If this is provided the user's nickname in the network will be the + string given here. If it is given, it must be UTF-8 encoded. If this + string is not given, the user's username by default is used as nickname. + The nickname may later be changed by using NICK command. The maximum + length for the nickname string is 128 bytes. */ + char *nickname; + /* If this key repository pointer is non-NULL then public key received in the key exchange protocol will be verified from this repository. If this is not provided then the `verify_public_key' client operation will @@ -1102,18 +1086,17 @@ SilcBool silc_client_key_exchange(SilcClient client, * * DESCRIPTION * - * Closes connection to remote end. Free's all allocated data except - * for some information such as nickname etc. that are valid at all time. - * Usually application does not need to directly call this, except - * when explicitly closing the connection, or if an error occurs - * during connection to server (see 'connect' client operation for - * more information). + * Closes the remote connection `conn'. The `conn' will become invalid + * after this call. Usually this function is called only when explicitly + * closing connection for example in case of error, or when the remote + * connection was created by the application or when the remote is client + * connection. Server connections are usually closed by sending QUIT + * command to the server. However, this call may also be used. * ***/ void silc_client_close_connection(SilcClient client, SilcClientConnection conn); - /* Message sending functions (client_channel.c and client_prvmsg.c) */ /****f* silcclient/SilcClientAPI/silc_client_send_channel_message diff --git a/lib/silcclient/silcclient_entry.h b/lib/silcclient/silcclient_entry.h index 60ba5f0a..ced8f4b1 100644 --- a/lib/silcclient/silcclient_entry.h +++ b/lib/silcclient/silcclient_entry.h @@ -410,12 +410,13 @@ void silc_client_get_clients_by_channel(SilcClient client, * * SYNOPSIS * - * void silc_client_get_clients_by_list(SilcClient client, - * SilcClientConnection conn, - * SilcUInt32 list_count, - * SilcBuffer client_id_list, - * SilcGetClientCallback completion, - * void *context); + * SilcUInt16 + * silc_client_get_clients_by_list(SilcClient client, + * SilcClientConnection conn, + * SilcUInt32 list_count, + * SilcBuffer client_id_list, + * SilcGetClientCallback completion, + * void *context); * * DESCRIPTION * @@ -428,18 +429,22 @@ void silc_client_get_clients_by_channel(SilcClient client, * accessed locally at a later time. The resolving is done with WHOIS * command. * + * Returns command identifier for the resolving. It can be used to attach + * a pending command to it, if needed. Returns 0 when no resolving was + * done or wasn't needed (completion is called before this returns). + * * NOTES * * If even after resolving some Client ID in the `client_id_list' is * unknown it will be ignored and error is not returned. * ***/ -void silc_client_get_clients_by_list(SilcClient client, - SilcClientConnection conn, - SilcUInt32 list_count, - SilcBuffer client_id_list, - SilcGetClientCallback completion, - void *context); +SilcUInt16 silc_client_get_clients_by_list(SilcClient client, + SilcClientConnection conn, + SilcUInt32 list_count, + SilcBuffer client_id_list, + SilcGetClientCallback completion, + void *context); /****f* silcclient/SilcClientAPI/silc_client_get_client_by_id * @@ -470,7 +475,7 @@ SilcClientEntry silc_client_get_client_by_id(SilcClient client, * * SYNOPSIS * - * void + * SilcUInt16 * silc_client_get_client_by_id_resolve(SilcClient client, * SilcClientConnection conn, * SilcClientID *client_id, @@ -487,6 +492,9 @@ SilcClientEntry silc_client_get_client_by_id(SilcClient client, * cache and can be accessed locally at a later time. The resolving * is done by sending WHOIS command. * + * Returns command identifier for the resolving. It can be used to attach + * a pending command to it, if needed. Returns 0 on error. + * * If the `attributes' is non-NULL then the buffer includes Requested * Attributes which can be used to fetch very detailed information * about the user. If it is NULL then only normal WHOIS query is @@ -495,12 +503,13 @@ SilcClientEntry silc_client_get_client_by_id(SilcClient client, * function. * ***/ -void silc_client_get_client_by_id_resolve(SilcClient client, - SilcClientConnection conn, - SilcClientID *client_id, - SilcBuffer attributes, - SilcGetClientCallback completion, - void *context); +SilcUInt16 +silc_client_get_client_by_id_resolve(SilcClient client, + SilcClientConnection conn, + SilcClientID *client_id, + SilcBuffer attributes, + SilcGetClientCallback completion, + void *context); /* SilcChannelEntry routines */ @@ -669,7 +678,7 @@ SilcChannelEntry silc_client_get_channel_by_id(SilcClient client, * * SYNOPSIS * - * void + * SilcUInt16 * silc_client_get_channel_by_id_resolve(SilcClient client, * SilcClientConnection conn, * SilcChannelID *channel_id, @@ -682,16 +691,20 @@ SilcChannelEntry silc_client_get_channel_by_id(SilcClient client, * by the `channel_id'. Use this only if you know that you do not have * the entry cached locally. The resolving is done with IDENTIFY command. * + * Returns command identifier for the resolving. It can be used to attach + * a pending command to it, if needed. Returns 0 on error. + * * Note that users on the channel are not resolved at the same time. * Use for example silc_client_get_clients_by_channel to resolve all * users on a channel. * ***/ -void silc_client_get_channel_by_id_resolve(SilcClient client, - SilcClientConnection conn, - SilcChannelID *channel_id, - SilcGetChannelCallback completion, - void *context); +SilcUInt16 +silc_client_get_channel_by_id_resolve(SilcClient client, + SilcClientConnection conn, + SilcChannelID *channel_id, + SilcGetChannelCallback completion, + void *context); /* SilcServerEntry routines */ @@ -819,7 +832,7 @@ SilcServerEntry silc_client_get_server_by_id(SilcClient client, * * SYNOPSIS * - * void + * SilcUInt16 * silc_client_get_server_by_id_resolve(SilcClient client, * SilcClientConnection conn, * SilcServerID *server_id, @@ -831,11 +844,15 @@ SilcServerEntry silc_client_get_server_by_id(SilcClient client, * Resolves the server information by the `server_id'. The resolved * server is returned into the `completion' callback. * + * Returns command identifier for the resolving. It can be used to attach + * a pending command to it, if needed. Returns 0 on error. + * ***/ -void silc_client_get_server_by_id_resolve(SilcClient client, - SilcClientConnection conn, - SilcServerID *server_id, - SilcGetServerCallback completion, - void *context); +SilcUInt16 +silc_client_get_server_by_id_resolve(SilcClient client, + SilcClientConnection conn, + SilcServerID *server_id, + SilcGetServerCallback completion, + void *context); #endif /* SILCCLIENT_ENTRY_H */ diff --git a/lib/silcclient/tests/test_silcclient.c b/lib/silcclient/tests/test_silcclient.c index f93a36f1..839b084b 100644 --- a/lib/silcclient/tests/test_silcclient.c +++ b/lib/silcclient/tests/test_silcclient.c @@ -26,7 +26,8 @@ typedef struct { static void silc_connected(SilcClient client, SilcClientConnection conn, - SilcClientConnectionStatus status, const char *message, + SilcClientConnectionStatus status, + SilcStatus error, const char *message, void *context) { MyBot mybot = client->application; @@ -72,14 +73,9 @@ int mybot_start(void) return 1; } - /* Now fill the allocated client with mandatory parameters the library - requires: username, hostname and "real name". */ - mybot->client->username = silc_get_username(); - mybot->client->hostname = silc_net_localhost(); - mybot->client->realname = strdup("I am the MyBot"); - /* Now we initialize the client. */ - if (!silc_client_init(mybot->client)) { + if (!silc_client_init(mybot->client, silc_get_username(), + silc_net_localhost(), "I am the MyBot")) { perror("Could not init client"); return 1; }