Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2006 Pekka Riikonen
+ Copyright (C) 2006 - 2007 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
SilcClient client;
SilcClientConnection conn;
SilcBufferStruct detach;
+ SilcBuffer auth;
char *nickname;
+ unsigned char *id;
+ SilcUInt32 id_len;
SilcUInt32 channel_count;
} *SilcClientResumeSession;
/************************ Static utility functions **************************/
-/* Command callback. Nothing interesting to do here. */
-
-static SilcBool
-silc_client_register_command_called(SilcClient client,
- SilcClientConnection conn,
- SilcCommand command,
- SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap)
-{
- return FALSE;
-}
-
/* Continues resuming after resolving. Continue after last reply. */
static SilcBool
va_end(ap);
}
+/* Resume authentication data generation callback */
+
+static void silc_client_resume_auth_generated(const SilcBuffer data,
+ void *context)
+{
+ SilcClientConnection conn = context;
+ SilcClientResumeSession resume =
+ silc_fsm_get_state_context(&conn->internal->event_thread);
+
+ if (!data)
+ silc_fsm_next(&conn->internal->event_thread, silc_client_st_resume_error);
+ else
+ resume->auth = silc_buffer_copy(data);
+
+ SILC_FSM_CALL_CONTINUE_SYNC(&conn->internal->event_thread);
+}
+
/****************************** NEW_ID packet *******************************/
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
SilcPacket packet = state_context;
+ char *nick;
SilcID id;
if (conn->local_id)
SILC_LOG_DEBUG(("New ID %s", silc_id_render(&id.u.client_id,
SILC_ID_CLIENT)));
+ /* From SILC protocol version 1.3, nickname is in NEW_CLIENT packet */
+ if (conn->internal->remote_version >= 13)
+ nick = (conn->internal->params.nickname ?
+ conn->internal->params.nickname : client->username);
+ else
+ nick = client->username;
+
/* Create local client entry */
- conn->local_entry = silc_client_add_client(client, conn,
- client->username,
+ conn->local_entry = silc_client_add_client(client, conn, nick,
client->username,
client->realname,
&id.u.client_id, 0);
{
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
+ char *nick = NULL;
SILC_LOG_DEBUG(("Register to network"));
+ /* From SILC protocol version 1.3, nickname is in NEW_CLIENT packet */
+ if (conn->internal->remote_version >= 13)
+ nick = (conn->internal->params.nickname ?
+ conn->internal->params.nickname : client->username);
+
/* Send NEW_CLIENT packet to register to network */
if (!silc_packet_send_va(conn->stream, SILC_PACKET_NEW_CLIENT, 0,
SILC_STR_UI_SHORT(strlen(client->username)),
SILC_STR_UI_SHORT(strlen(client->realname)),
SILC_STR_DATA(client->realname,
strlen(client->realname)),
+ SILC_STR_UI_SHORT(nick ? strlen(nick) : 0),
+ SILC_STR_DATA(nick, nick ? strlen(nick) : 0),
SILC_STR_END)) {
/** Error sending packet */
silc_fsm_next(fsm, silc_client_st_register_error);
/* Issue IDENTIFY command for itself to get resolved hostname
correctly from server. */
silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
- silc_client_register_command_called, NULL,
+ silc_client_command_called_dummy, NULL,
1, 5, silc_buffer_data(conn->internal->local_idp),
silc_buffer_len(conn->internal->local_idp));
- /* Call NICK command if the nickname was set by the application (and is
- not same as the username). */
- if (conn->internal->params.nickname &&
+ /* With SILC protocol version 1.2 call NICK command if the nickname was
+ set by the application. */
+ if (conn->internal->params.nickname && conn->internal->remote_version < 13 &&
!silc_utf8_strcasecmp(conn->internal->params.nickname, client->username))
silc_client_command_call(client, conn, NULL,
"NICK", conn->internal->params.nickname, NULL);
/* Issue INFO command to fetch the real server name and server
information and other stuff. */
silc_client_command_send(client, conn, SILC_COMMAND_INFO,
- silc_client_register_command_called, NULL,
+ silc_client_command_called_dummy, NULL,
1, 2, silc_buffer_data(conn->internal->remote_idp),
silc_buffer_len(conn->internal->remote_idp));
conn->internal->registering = FALSE;
silc_schedule_task_del_by_all(conn->internal->schedule, 0,
silc_client_connect_timeout, conn);
+ silc_async_free(conn->internal->cop);
+ conn->internal->cop = NULL;
return SILC_FSM_FINISH;
}
SILC_FSM_STATE(silc_client_st_register_error)
{
SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
SILC_LOG_DEBUG(("Error registering to network"));
/* Signal to close connection */
+ conn->internal->status = SILC_CLIENT_CONN_ERROR;
if (!conn->internal->disconnected) {
conn->internal->disconnected = TRUE;
- SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+ SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
}
- /* Call connect callback */
- if (conn->internal->callback_called)
- conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
- conn->callback_context);
- conn->internal->callback_called = TRUE;
-
silc_schedule_task_del_by_all(conn->internal->schedule, 0,
silc_client_connect_timeout, conn);
SilcClientConnection conn = fsm_context;
SilcClient client = conn->client;
SilcClientResumeSession resume;
- SilcBuffer auth;
unsigned char *id;
SilcUInt16 id_len;
SilcClientID client_id;
silc_fsm_next(fsm, silc_client_st_resume_error);
return SILC_FSM_CONTINUE;
}
+ resume->id = id;
+ resume->id_len = id_len;
/* 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,
- &client_id, SILC_ID_CLIENT);
- if (!auth) {
- /** Out of memory */
- silc_fsm_next(fsm, silc_client_st_resume_error);
- return SILC_FSM_CONTINUE;
- }
+ silc_fsm_next(fsm, silc_client_st_resume_send);
+ SILC_FSM_CALL(silc_auth_public_key_auth_generate(
+ conn->public_key, conn->private_key,
+ client->rng, conn->internal->hash,
+ &client_id, SILC_ID_CLIENT,
+ silc_client_resume_auth_generated, conn));
+ /* NOT REACHED */
+}
+
+/* Send RESUME_CLIENT packet */
+
+SILC_FSM_STATE(silc_client_st_resume_send)
+{
+ SilcClientConnection conn = fsm_context;
+ SilcClientResumeSession resume = state_context;
+
+ SILC_LOG_DEBUG(("Send RESUME_CLIENT packet"));
/* 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_DATA(id, id_len),
- SILC_STR_DATA(silc_buffer_data(auth),
- silc_buffer_len(auth)),
+ SILC_STR_UI_SHORT(resume->id_len),
+ SILC_STR_DATA(resume->id, resume->id_len),
+ SILC_STR_DATA(silc_buffer_data(resume->auth),
+ silc_buffer_len(resume->auth)),
SILC_STR_END)) {
/** Error sending packet */
SILC_LOG_DEBUG(("Error sending packet"));
return SILC_FSM_CONTINUE;
}
+ /** Wait for channels */
+ silc_fsm_next(fsm, silc_client_st_resume_resolve_cmodes);
+
/* Change our nickname */
silc_client_change_nickname(client, conn, conn->local_entry,
resume->nickname, NULL, NULL, 0);
/* Send UMODE command to get our own user mode in the network */
SILC_LOG_DEBUG(("Resolving user mode"));
silc_client_command_send(client, conn, SILC_COMMAND_UMODE,
- silc_client_register_command_called, NULL,
+ silc_client_command_called_dummy, NULL,
1, 1, silc_buffer_data(conn->internal->local_idp),
silc_buffer_len(conn->internal->local_idp));
+ if (!resume->channel_count)
+ return SILC_FSM_YIELD;
+
/* Send IDENTIFY command for all channels we know about. These are the
channels we've joined to according our detachment data. */
for (i = 0; i < resume->channel_count; i++) {
channel = silc_client_get_channel_by_id(client, conn, &channel_id);
if (!channel)
silc_client_add_channel(client, conn, name, 0, &channel_id);
+ else
+ silc_client_unref_channel(client, conn, channel);
res_argv = silc_realloc(res_argv, sizeof(*res_argv) * (res_argc + 1));
res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
silc_free(res_argv_lens);
silc_free(res_argv_types);
- /** Wait for channels */
- silc_fsm_next(fsm, silc_client_st_resume_resolve_cmodes);
return SILC_FSM_WAIT;
}
silc_fsm_next(fsm, silc_client_st_resume_completed);
if (!silc_idcache_get_all(conn->internal->channel_cache, &channels))
- return SILC_FSM_CONTINUE;
+ return SILC_FSM_YIELD;
/* Resolve channels' mode, users and topic */
resume->channel_count = silc_list_count(channels) * 3;
/* Issue IDENTIFY command for itself to get resolved hostname
correctly from server. */
silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
- silc_client_register_command_called, NULL,
+ silc_client_command_called_dummy, NULL,
1, 5, silc_buffer_data(conn->internal->local_idp),
silc_buffer_len(conn->internal->local_idp));
/* Issue INFO command to fetch the real server name and server
information and other stuff. */
silc_client_command_send(client, conn, SILC_COMMAND_INFO,
- silc_client_register_command_called, NULL,
+ silc_client_command_called_dummy, NULL,
1, 2, silc_buffer_data(conn->internal->remote_idp),
silc_buffer_len(conn->internal->remote_idp));
conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS_RESUME, 0, NULL,
conn->callback_context);
+ /* Call UMODE command reply. */
+ if (conn->local_entry->mode)
+ silc_client_resume_command_callback(client, conn, SILC_COMMAND_UMODE,
+ conn->local_entry->mode);
+
/* Call NICK command reply. */
silc_client_resume_command_callback(client, conn, SILC_COMMAND_NICK,
conn->local_entry,
const char *cipher, *hmac;
channel = entry->context;
- cipher = (channel->internal.channel_key ?
- silc_cipher_get_name(channel->internal.channel_key) : NULL);
+ cipher = (channel->internal.send_key ?
+ silc_cipher_get_name(channel->internal.send_key) : NULL);
hmac = (channel->internal.hmac ?
silc_hmac_get_name(channel->internal.hmac) : NULL);
silc_hash_table_list(channel->user_list, &htl);
silc_client_connect_timeout, conn);
silc_free(resume->nickname);
silc_free(resume);
+ silc_async_free(conn->internal->cop);
+ conn->internal->cop = NULL;
return SILC_FSM_FINISH;
}
SILC_FSM_STATE(silc_client_st_resume_error)
{
SilcClientConnection conn = fsm_context;
- SilcClient client = conn->client;
SilcClientResumeSession resume = state_context;
if (conn->internal->disconnected) {
SILC_LOG_DEBUG(("Error resuming to network"));
/* Signal to close connection */
+ conn->internal->status = SILC_CLIENT_CONN_ERROR;
if (!conn->internal->disconnected) {
conn->internal->disconnected = TRUE;
- SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+ SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event);
}
- /* Call connect callback */
- if (conn->internal->callback_called)
- conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
- conn->callback_context);
- conn->internal->callback_called = TRUE;
-
silc_schedule_task_del_by_all(conn->internal->schedule, 0,
silc_client_connect_timeout, conn);