*/
/* $Id$ */
-#include "clientlibincludes.h"
+#include "silcincludes.h"
+#include "silcclient.h"
#include "client_internal.h"
/* Static task callback prototypes */
void silc_client_resolve_auth_method(bool success,
SilcProtocolAuthMeth auth_meth,
const unsigned char *auth_data,
- uint32 auth_data_len, void *context);
+ SilcUInt32 auth_data_len, void *context);
/* Allocates new client object. This has to be done before client may
work. After calling this one must call silc_client_init to initialize
SILC_LOG_DEBUG(("Initializing client"));
/* Initialize hash functions for client to use */
- silc_hash_alloc("md5", &client->internal->md5hash);
- silc_hash_alloc("sha1", &client->internal->sha1hash);
+ silc_hash_alloc("md5", &client->md5hash);
+ silc_hash_alloc("sha1", &client->sha1hash);
/* Initialize none cipher */
silc_cipher_alloc("none", &client->internal->none_cipher);
/* Initialize the scheduler */
client->schedule =
silc_schedule_init(client->internal->params->task_max ?
- client->internal->params->task_max : 200);
+ client->internal->params->task_max : 200, client);
if (!client->schedule)
return FALSE;
application performed the connecting outside the library. The library
however may use this internally. */
-SilcClientConnection silc_client_add_connection(SilcClient client,
- char *hostname,
- int port,
- void *context)
+SilcClientConnection
+silc_client_add_connection(SilcClient client,
+ SilcClientConnectionParams *params,
+ char *hostname, int port, void *context)
{
SilcClientConnection conn;
int i;
+ SILC_LOG_DEBUG(("Adding new connection to %s:%d", hostname, port));
+
conn = silc_calloc(1, sizeof(*conn));
/* Initialize ID caches */
conn->pending_commands = silc_dlist_init();
conn->ftp_sessions = silc_dlist_init();
+ if (params) {
+ if (params->detach_data)
+ conn->params.detach_data = silc_memdup(params->detach_data,
+ params->detach_data_len);
+ conn->params.detach_data_len = params->detach_data_len;
+ }
+
/* Add the connection to connections table */
for (i = 0; i < client->internal->conns_count; i++)
if (client->internal->conns && !client->internal->conns[i]) {
if (conn->pending_commands)
silc_dlist_uninit(conn->pending_commands);
silc_free(conn->remote_host);
- silc_dlist_uninit(conn->ftp_sessions);
+ if (conn->ftp_sessions)
+ silc_dlist_uninit(conn->ftp_sessions);
silc_free(conn);
client->internal->conns[i] = NULL;
case then this function is not used at all. When the connecting is
done the `connect' client operation is called. */
-int silc_client_connect_to_server(SilcClient client, int port,
- char *host, void *context)
+int silc_client_connect_to_server(SilcClient client,
+ SilcClientConnectionParams *params,
+ int port, char *host, void *context)
{
SilcClientInternalConnectContext *ctx;
SilcClientConnection conn;
SILC_LOG_DEBUG(("Connecting to port %d of server %s",
port, host));
- conn = silc_client_add_connection(client, host, port, context);
+ conn = silc_client_add_connection(client, params, host, port, context);
client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
"Connecting to port %d of server %s", port, host);
SILC_LOG_DEBUG(("Start"));
- /* XXX We should most likely use the resolved host name instead of the
- one user provided for us. */
- silc_free(conn->sock->hostname);
- conn->sock->hostname = strdup(conn->remote_host);
+ if (conn->sock->hostname) {
+ silc_free(conn->remote_host);
+ conn->remote_host = strdup(conn->sock->hostname);
+ } else {
+ conn->sock->hostname = strdup(conn->remote_host);
+ }
if (!conn->sock->ip)
- conn->sock->ip = strdup(conn->remote_host);
+ conn->sock->ip = strdup(conn->sock->hostname);
conn->sock->port = conn->remote_port;
/* Allocate internal Key Exchange context. This is sent to the
client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
"Error: Could not start key exchange protocol");
silc_net_close_connection(conn->sock->sock);
- client->internal->ops->connect(client, conn, FALSE);
+ client->internal->ops->connect(client, conn, SILC_CLIENT_CONN_ERROR);
return;
}
conn->sock->protocol = protocol;
(SilcClientKEInternalContext *)context;
SilcClient client = (SilcClient)ctx->client;
- client->internal->ops->connect(client, ctx->sock->user_data, FALSE);
+ client->internal->ops->connect(client, ctx->sock->user_data,
+ SILC_CLIENT_CONN_ERROR);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
silc_free(ctx);
silc_free(ctx);
/* Notify application of failure */
- client->internal->ops->connect(client, conn, FALSE);
+ client->internal->ops->connect(client, conn, SILC_CLIENT_CONN_ERROR);
silc_client_del_connection(client, conn);
}
return;
void silc_client_resolve_auth_method(bool success,
SilcProtocolAuthMeth auth_meth,
const unsigned char *auth_data,
- uint32 auth_data_len, void *context)
+ SilcUInt32 auth_data_len, void *context)
{
SilcClientConnAuthInternalContext *proto_ctx =
(SilcClientConnAuthInternalContext *)context;
proto_ctx->auth_meth = auth_meth;
if (auth_data && auth_data_len) {
- proto_ctx->auth_data = silc_calloc(auth_data_len, sizeof(*auth_data));
- memcpy(proto_ctx->auth_data, auth_data, auth_data_len);
+ proto_ctx->auth_data = silc_memdup(auth_data, auth_data_len);
proto_ctx->auth_data_len = auth_data_len;
}
protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
SILC_LOG_DEBUG(("Error during authentication protocol"));
- silc_protocol_free(protocol);
- if (ctx->auth_data)
- silc_free(ctx->auth_data);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
- if (ctx->dest_id)
- silc_free(ctx->dest_id);
- conn->sock->protocol = NULL;
- silc_socket_free(ctx->sock);
-
- /* Notify application of failure */
- silc_schedule_task_add(client->schedule, ctx->sock->sock,
- silc_client_connect_failure, ctx,
- 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
- return;
+ goto err;
}
- /* Send NEW_CLIENT packet to the server. We will become registered
- to the SILC network after sending this packet and we will receive
- client ID from the server. */
- packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
- strlen(client->realname));
- silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
- silc_buffer_format(packet,
- SILC_STR_UI_SHORT(strlen(client->username)),
- SILC_STR_UI_XNSTRING(client->username,
- strlen(client->username)),
- SILC_STR_UI_SHORT(strlen(client->realname)),
- SILC_STR_UI_XNSTRING(client->realname,
- strlen(client->realname)),
- SILC_STR_END);
+ if (conn->params.detach_data) {
+ /* Send RESUME_CLIENT packet to the server, which is used to resume
+ old detached session back. */
+ SilcBuffer auth;
+ SilcClientID *old_client_id;
+ unsigned char *old_id;
+ SilcUInt16 old_id_len;
+
+ if (!silc_client_process_detach_data(client, conn, &old_id, &old_id_len))
+ goto err;
+
+ old_client_id = silc_id_str2id(old_id, old_id_len, SILC_ID_CLIENT);
+ if (!old_client_id) {
+ silc_free(old_id);
+ goto err;
+ }
- /* Send the packet */
- silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
- NULL, 0, NULL, NULL,
- packet->data, packet->len, TRUE);
- silc_buffer_free(packet);
+ /* Generate authentication data that server will verify */
+ auth = silc_auth_public_key_auth_generate(client->public_key,
+ client->private_key,
+ client->rng, conn->hash,
+ old_client_id, SILC_ID_CLIENT);
+ if (!auth) {
+ silc_free(old_client_id);
+ silc_free(old_id);
+ goto err;
+ }
+
+ packet = silc_buffer_alloc_size(2 + old_id_len + auth->len);
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(old_id_len),
+ SILC_STR_UI_XNSTRING(old_id, old_id_len),
+ SILC_STR_UI_XNSTRING(auth->data, auth->len),
+ SILC_STR_END);
+
+ /* Send the packet */
+ silc_client_packet_send(client, ctx->sock, SILC_PACKET_RESUME_CLIENT,
+ NULL, 0, NULL, NULL,
+ packet->data, packet->len, TRUE);
+ silc_buffer_free(packet);
+ silc_buffer_free(auth);
+ silc_free(old_client_id);
+ silc_free(old_id);
+ } else {
+ /* Send NEW_CLIENT packet to the server. We will become registered
+ to the SILC network after sending this packet and we will receive
+ client ID from the server. */
+ packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
+ strlen(client->realname));
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(strlen(client->username)),
+ SILC_STR_UI_XNSTRING(client->username,
+ strlen(client->username)),
+ SILC_STR_UI_SHORT(strlen(client->realname)),
+ SILC_STR_UI_XNSTRING(client->realname,
+ strlen(client->realname)),
+ SILC_STR_END);
+
+ /* Send the packet */
+ silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
+ NULL, 0, NULL, NULL,
+ packet->data, packet->len, TRUE);
+ silc_buffer_free(packet);
+ }
/* Save remote ID. */
conn->remote_id = ctx->dest_id;
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
silc_protocol_free(protocol);
- if (ctx->auth_data)
- silc_free(ctx->auth_data);
+ silc_free(ctx->auth_data);
if (ctx->ske)
silc_ske_free(ctx->ske);
silc_socket_free(ctx->sock);
silc_free(ctx);
conn->sock->protocol = NULL;
+ return;
+
+ err:
+ silc_protocol_free(protocol);
+ silc_free(ctx->auth_data);
+ silc_free(ctx->dest_id);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ conn->sock->protocol = NULL;
+ silc_socket_free(ctx->sock);
+
+ /* Notify application of failure */
+ silc_schedule_task_add(client->schedule, ctx->sock->sock,
+ silc_client_connect_failure, ctx,
+ 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
/* Internal routine that sends packet or marks packet to be sent. This
if (SILC_IS_DISCONNECTED(sock))
return;
- if (sock->outbuf->data - sock->outbuf->head)
- silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
-
ret = silc_packet_send(sock, TRUE);
/* If returned -2 could not write to connection now, will do
close the connection */
if (SILC_IS_DISCONNECTING(sock)) {
if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
- client->internal->ops->disconnect(client, conn);
- silc_client_close_connection(client, sock, conn);
+ client->internal->ops->disconnect(client, conn, 0, NULL);
+ silc_client_close_connection_real(client, sock, conn);
return;
}
SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
- client->internal->ops->disconnect(client, conn);
- silc_client_close_connection(client, sock, conn);
+ client->internal->ops->disconnect(client, conn, 0, NULL);
+ silc_client_close_connection_real(client, sock, conn);
return;
}
SilcBuffer buffer = packet->buffer;
SilcPacketType type = packet->type;
- SILC_LOG_DEBUG(("Parsing packet type %d", type));
+ SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(type)));
/* Parse the packet type */
switch(type) {
+
case SILC_PACKET_DISCONNECT:
silc_client_disconnected_by_server(client, sock, buffer);
break;
+
case SILC_PACKET_SUCCESS:
/*
* Success received for something. For now we can have only
if (sock->protocol)
silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
break;
+
case SILC_PACKET_FAILURE:
/*
* Failure received for some protocol. Set the protocol state to
*/
silc_client_process_failure(client, sock, packet);
break;
+
case SILC_PACKET_REJECT:
break;
*/
silc_client_channel_message(client, sock, packet);
break;
+
case SILC_PACKET_CHANNEL_KEY:
/*
* Received key for a channel. By receiving this key the client will be
*/
silc_client_private_message(client, sock, packet);
break;
+
case SILC_PACKET_PRIVATE_MESSAGE_KEY:
/*
* Received private message key
*/
break;
+ case SILC_PACKET_COMMAND:
+ /*
+ * Received command packet, a special case since normally client
+ * does not receive commands.
+ */
+ silc_client_command_process(client, sock, packet);
+ break;
+
case SILC_PACKET_COMMAND_REPLY:
/*
* Recived reply for a command
"protocol active, packet dropped."));
}
break;
+
case SILC_PACKET_KEY_EXCHANGE_2:
if (sock->protocol && sock->protocol->protocol &&
(sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
SilcCipher cipher,
SilcHmac hmac,
unsigned char *data,
- uint32 data_len,
+ SilcUInt32 data_len,
int force_send)
{
SilcPacketContext packetdata;
+ const SilcBufferStruct packet;
int block_len;
- uint32 sequence = 0;
+ SilcUInt32 sequence = 0;
if (!sock)
return;
packetdata.dst_id_len = 0;
packetdata.dst_id_type = SILC_ID_NONE;
}
+ data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len +
+ packetdata.dst_id_len));
packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
packetdata.src_id_len + packetdata.dst_id_len;
packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
- /* Prepare outgoing data buffer for packet sending */
- silc_packet_send_prepare(sock,
- SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len +
- packetdata.dst_id_len,
- packetdata.padlen,
- data_len);
-
- SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
-
- packetdata.buffer = sock->outbuf;
-
- /* Put the data to the buffer */
- if (data && data_len)
- silc_buffer_put(sock->outbuf, data, data_len);
-
/* Create the outgoing packet */
- silc_packet_assemble(&packetdata, cipher);
+ if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
+ data, data_len, (const SilcBuffer)&packet)) {
+ SILC_LOG_ERROR(("Error assembling packet"));
+ return;
+ }
/* Encrypt the packet */
if (cipher)
- silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf,
- sock->outbuf->len);
+ silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet,
+ packet.len);
- SILC_LOG_HEXDUMP(("Packet (%d), len %d", sequence, sock->outbuf->len),
- sock->outbuf->data, sock->outbuf->len);
+ SILC_LOG_HEXDUMP(("Packet (%d), len %d", sequence, packet.len),
+ packet.data, packet.len);
/* Now actually send the packet */
silc_client_packet_send_real(client, sock, force_send);
{
if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
(SILC_IS_DISCONNECTED(sock) == FALSE)) {
- if (sock->outbuf->data - sock->outbuf->head)
- silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
-
silc_packet_send(sock, TRUE);
-
SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, sock->sock);
SILC_UNSET_OUTBUF_PENDING(sock);
silc_buffer_clear(sock->outbuf);
connection but `conn->sock' might be actually a different connection
than the `sock'). */
-void silc_client_close_connection(SilcClient client,
- SilcSocketConnection sock,
- SilcClientConnection conn)
+void silc_client_close_connection_real(SilcClient client,
+ SilcSocketConnection sock,
+ SilcClientConnection conn)
{
int del = FALSE;
SILC_LOG_DEBUG(("Start"));
+ if (!sock && !conn)
+ return;
+
if (!sock || (sock && conn->sock == sock))
del = TRUE;
if (!sock)
/* Unregister all tasks */
silc_schedule_task_del_by_fd(client->schedule, sock->sock);
- silc_schedule_task_del_by_fd(client->schedule, sock->sock);
/* Close the actual connection */
silc_net_close_connection(sock->sock);
/* Free all cache entries */
SilcIDCacheList list;
SilcIDCacheEntry entry;
+ SilcClientCommandPending *r;
bool ret;
if (silc_idcache_get_all(conn->client_cache, &list)) {
silc_hmac_free(conn->hmac_send);
if (conn->hmac_receive)
silc_hmac_free(conn->hmac_receive);
- if (conn->pending_commands)
- silc_dlist_uninit(conn->pending_commands);
if (conn->rekey)
silc_free(conn->rekey);
silc_client_ftp_free_sessions(client, conn);
+ silc_dlist_start(conn->pending_commands);
+ while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END)
+ silc_dlist_del(conn->pending_commands, r);
+ if (conn->pending_commands)
+ silc_dlist_uninit(conn->pending_commands);
+
memset(conn, 0, sizeof(*conn));
silc_client_del_connection(client, conn);
}
silc_socket_free(sock);
}
+/* Closes the connection to the remote end */
+
+void silc_client_close_connection(SilcClient client,
+ SilcClientConnection conn)
+{
+ silc_client_close_connection_real(client, NULL, conn);
+}
+
/* Called when we receive disconnection packet from server. This
closes our end properly and displays the reason of the disconnection
on the screen. */
if (sock == NULL)
return;
- silc_client_close_connection(client, sock, sock->user_data);
+ silc_client_close_connection_real(client, sock, sock->user_data);
}
/* Called when we receive disconnection packet from server. This
void silc_client_disconnected_by_server(SilcClient client,
SilcSocketConnection sock,
- SilcBuffer message)
+ SilcBuffer packet)
{
- char *msg;
+ SilcClientConnection conn;
+ SilcStatus status;
+ char *message = NULL;
SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
- msg = silc_calloc(message->len + 1, sizeof(char));
- memcpy(msg, message->data, message->len);
- client->internal->ops->say(client, sock->user_data,
- SILC_CLIENT_MESSAGE_AUDIT, msg);
- silc_free(msg);
+ if (packet->len < 1)
+ return;
+
+ status = (SilcStatus)packet->data[0];
+
+ if (packet->len > 1 &&
+ silc_utf8_valid(packet->data + 1, packet->len - 1))
+ message = silc_memdup(packet->data + 1, packet->len - 1);
+
+ conn = (SilcClientConnection)sock->user_data;
+ if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
+ client->internal->ops->disconnect(client, conn, status, message);
+
+ silc_free(message);
SILC_SET_DISCONNECTED(sock);
{
char *msg;
- msg = silc_calloc(message->len + 1, sizeof(char));
- memcpy(msg, message->data, message->len);
+ msg = silc_memdup(message->data, message->len);
client->internal->ops->say(client, sock->user_data,
SILC_CLIENT_MESSAGE_AUDIT, msg);
silc_free(msg);
}
+/* Auto-nicking callback to send NICK command to server. */
+
+SILC_TASK_CALLBACK(silc_client_send_auto_nick)
+{
+ SilcClientConnection conn = (SilcClientConnection)context;
+ SilcClient client = conn->client;
+
+ silc_client_command_send(client, conn, SILC_COMMAND_NICK,
+ ++conn->cmd_ident, 1, 1,
+ client->nickname, strlen(client->nickname));
+}
+
+/* Client session resuming callback. If the session was resumed
+ this callback is called after the resuming is completed. This
+ will call the `connect' client operation to the application
+ since it has not been called yet. */
+
+static void silc_client_resume_session_cb(SilcClient client,
+ SilcClientConnection conn,
+ bool success,
+ void *context)
+{
+ SilcBuffer sidp;
+
+ /* Notify application that connection is created to server */
+ client->internal->ops->connect(client, conn, success ?
+ SILC_CLIENT_CONN_SUCCESS_RESUME :
+ SILC_CLIENT_CONN_ERROR);
+
+ if (success) {
+ /* Issue INFO command to fetch the real server name and server
+ information and other stuff. */
+ silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
+ silc_client_command_reply_info_i, 0,
+ ++conn->cmd_ident);
+ sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
+ silc_client_command_send(client, conn, SILC_COMMAND_INFO,
+ conn->cmd_ident, 1, 2, sidp->data, sidp->len);
+ silc_buffer_free(sidp);
+ }
+}
+
/* Processes the received new Client ID from server. Old Client ID is
deleted from cache and new one is added. */
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
int connecting = FALSE;
SilcClientID *client_id = silc_id_payload_get_id(idp);
- SilcBuffer sidp;
if (!conn->local_entry)
connecting = TRUE;
conn->local_entry->nickname = conn->nickname;
if (!conn->local_entry->username)
conn->local_entry->username = strdup(client->username);
- if (!conn->local_entry->hostname)
- conn->local_entry->hostname = strdup(client->hostname);
- conn->local_entry->server = strdup(conn->remote_host);
+ if (!conn->local_entry->server)
+ conn->local_entry->server = strdup(conn->remote_host);
conn->local_entry->id = conn->local_id;
conn->local_entry->valid = TRUE;
- conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr,
- NULL, NULL,
- NULL, NULL, NULL, TRUE);
+ if (!conn->local_entry->channels)
+ conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr,
+ NULL, NULL,
+ NULL, NULL, NULL,
+ TRUE);
/* Put it to the ID cache */
silc_idcache_add(conn->client_cache, strdup(conn->nickname), conn->local_id,
(void *)conn->local_entry, 0, NULL);
if (connecting) {
- /* Send NICK command if the nickname was set by the application (and is
- not same as the username). */
- if (client->nickname && strcmp(client->nickname, client->username))
- silc_client_command_send(client, conn, SILC_COMMAND_NICK,
- ++conn->cmd_ident, 1, 1,
- client->nickname, strlen(client->nickname));
-
- /* Issue INFO command to fetch the real server name and server information
- and other stuff. */
- silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
- silc_client_command_reply_info_i, 0,
+ SilcBuffer sidp;
+
+ /* Issue IDENTIFY command for itself to get resolved hostname
+ correctly from server. */
+ silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
+ silc_client_command_reply_identify_i, 0,
++conn->cmd_ident);
- sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
- silc_client_command_send(client, conn, SILC_COMMAND_INFO,
- conn->cmd_ident, 1, 2, sidp->data, sidp->len);
+ sidp = silc_id_payload_encode(conn->local_entry->id, SILC_ID_CLIENT);
+ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident, 1, 5, sidp->data, sidp->len);
silc_buffer_free(sidp);
- /* Notify application of successful connection. We do it here now that
- we've received the Client ID and are allowed to send traffic. */
- client->internal->ops->connect(client, conn, TRUE);
+ if (!conn->params.detach_data) {
+ /* 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 && strcmp(client->nickname, client->username))
+ silc_schedule_task_add(client->schedule, 0,
+ silc_client_send_auto_nick, conn,
+ 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
+ /* Notify application of successful connection. We do it here now that
+ we've received the Client ID and are allowed to send traffic. */
+ client->internal->ops->connect(client, conn, SILC_CLIENT_CONN_SUCCESS);
+
+ /* Issue INFO command to fetch the real server name and server
+ information and other stuff. */
+ silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
+ silc_client_command_reply_info_i, 0,
+ ++conn->cmd_ident);
+ sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
+ silc_client_command_send(client, conn, SILC_COMMAND_INFO,
+ conn->cmd_ident, 1, 2, sidp->data, sidp->len);
+ silc_buffer_free(sidp);
+ } else {
+ /* We are resuming session. Start resolving informations from the
+ server we need to set the client libary in the state before
+ detaching the session. The connect client operation is called
+ after this is successfully completed */
+ silc_client_resume_session(client, conn, silc_client_resume_session_cb,
+ NULL);
+ }
}
}
SilcChannelUser chu;
silc_hash_table_list(client_entry->channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
+ while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
silc_hash_table_del(chu->client->channels, chu->channel);
silc_hash_table_del(chu->channel->user_list, chu->client);
silc_free(chu);
}
+
silc_hash_table_list_reset(&htl);
}
SilcChannelUser chu;
silc_hash_table_list(old->channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
+ while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
/* Replace client entry */
silc_hash_table_del(chu->client->channels, chu->channel);
silc_hash_table_del(chu->channel->user_list, chu->client);
SilcSocketConnection sock,
SilcPacketContext *packet)
{
- uint32 failure = 0;
+ SilcUInt32 failure = 0;
if (sock->protocol) {
if (packet->buffer->len >= 4)
SilcPacketContext *packet)
{
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
- uint16 conn_type, auth_meth;
+ SilcUInt16 conn_type, auth_meth;
int ret;
/* If we haven't send our request then ignore this one. */