client_connect.c \
client_register.c \
client_notify.c \
+ client_attrs.c \
command.c \
command_reply.c
/* 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);
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;
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);
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,
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
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);
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
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);
/* 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;
/* 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;
}
silc_schedule_stop(client->schedule);
silc_schedule_uninit(client->schedule);
-
silc_client_commands_unregister(client);
SILC_LOG_DEBUG(("Client stopped"));
{
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);
}
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;
/* 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 :
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;
/* 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;
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,
SilcChannelUser chu;
if (silc_client_on_channel(channel, client_entry))
- return FALSE;
+ return TRUE;
chu = silc_calloc(1, sizeof(*chu));
if (!chu)
/* 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;
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);
"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);
}
/** 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;
}
/** 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;
}
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;
}
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;
}
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;
}
/* Call connection callback */
conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
- conn->context);
+ conn->callback_context);
return SILC_FSM_FINISH;
}
/* 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;
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 */
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 */
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)
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
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;
/* 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);
silc_free(res_argv);
silc_free(res_argv_lens);
silc_free(res_argv_types);
+ return 0;
}
#if 0
/* 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;
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 */
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 ***************************/
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)) {
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;
}
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);
/* 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;
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 */
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 */
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 ***************************/
/* 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;
/* 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 */
/* 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);
#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. */
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 ***********************************/
SILC_FSM_STATE(silc_client_notify)
{
SilcPacket packet = state_context;
+ SilcClientNotify notify;
SilcNotifyPayload payload;
payload = silc_notify_payload_parse(silc_buffer_data(&packet->buffer),
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)) {
/** Unknown notify */
silc_notify_payload_free(payload);
silc_packet_free(packet);
+ silc_free(notify);
return SILC_FSM_FINISH;
break;
}
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;
}
{
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);
{
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;
/* 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;
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));
{
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;
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;
!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));
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);
{
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;
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;
{
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;
{
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;
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;
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));
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));
&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));
{
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;
{
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;
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)
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));
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));
&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));
{
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;
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)
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));
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));
&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));
{
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;
{
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;
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;
{
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;
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;
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;
/** 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));
{
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;
{
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;
{
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;
{
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;
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);
}
/* 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;
/* 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)
/* 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;
/************************** 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 **************************/
/* 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);
/* 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,
/* 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);
}
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;
/* 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;
/* 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;
}
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;
}
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;
+}
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 */
Author: Pekka Riikonen <priikone@silcnet.org>
- 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
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)
/* 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;
}
/* 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;
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);
}
}
/* 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);
/* 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());
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")) {
}
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);
/* 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,
/* 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 */
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);
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;
/* 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]);
}
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 */
SilcChannelEntry channel;
unsigned char *tmp;
SilcUInt32 len;
- SilcBufferStruct buf;
+ SilcArgumentPayload invite_args = NULL;
SilcID id;
/* Sanity checks */
/* 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);
/********************************** 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)
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;
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) {
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 */
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);
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++) {
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);
/* 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;
}
SilcChannelEntry channel;
unsigned char *tmp;
SilcUInt32 len;
- SilcBufferStruct buf;
+ SilcArgumentPayload invite_args = NULL;
SilcID id;
/* Sanity checks */
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);
/********************************* 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,
SILC_FSM_CALL_CONTINUE(&cmd->thread);
}
+
/* Continue USERS command after resolving unknown channel */
static void
/* 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;
* 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;
};
/***/
*
* 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 */
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;
};
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
*
* SYNOPSIS
*
- * SilcBool silc_client_init(SilcClient client);
+ * SilcBool silc_client_init(SilcClient client, const char *username,
+ * const char *hostname, const char *realname);
*
* DESCRIPTION
*
* 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
*
* 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
*
* 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
*
* 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
*
* 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
*
*
* SYNOPSIS
*
- * void
+ * SilcUInt16
* silc_client_get_client_by_id_resolve(SilcClient client,
* SilcClientConnection conn,
* SilcClientID *client_id,
* 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
* 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 */
*
* SYNOPSIS
*
- * void
+ * SilcUInt16
* silc_client_get_channel_by_id_resolve(SilcClient client,
* SilcClientConnection conn,
* SilcChannelID *channel_id,
* 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 */
*
* SYNOPSIS
*
- * void
+ * SilcUInt16
* silc_client_get_server_by_id_resolve(SilcClient client,
* SilcClientConnection conn,
* SilcServerID *server_id,
* 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 */
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;
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;
}