More client library rewrites.
authorPekka Riikonen <priikone@silcnet.org>
Tue, 28 Nov 2006 20:29:06 +0000 (20:29 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Tue, 28 Nov 2006 20:29:06 +0000 (20:29 +0000)
18 files changed:
lib/silcclient/Makefile.ad
lib/silcclient/client.c
lib/silcclient/client.h
lib/silcclient/client_attrs.c
lib/silcclient/client_channel.c
lib/silcclient/client_connect.c
lib/silcclient/client_entry.c
lib/silcclient/client_internal.h
lib/silcclient/client_notify.c
lib/silcclient/client_prvmsg.c
lib/silcclient/client_register.c
lib/silcclient/client_register.h
lib/silcclient/client_resume.c
lib/silcclient/command.c
lib/silcclient/command_reply.c
lib/silcclient/silcclient.h
lib/silcclient/silcclient_entry.h
lib/silcclient/tests/test_silcclient.c

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