updates.
[silc.git] / lib / silcclient / client.c
index 3e0032f673df36152bd9150b3b43032188ff8fe0..fe6705968ec2764b9120cbc992ddb9f430aacf6b 100644 (file)
@@ -26,7 +26,6 @@
 SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
 SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
 SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
-SILC_TASK_CALLBACK(silc_client_packet_parse_real);
 SILC_TASK_CALLBACK(silc_client_rekey_callback);
 SILC_TASK_CALLBACK(silc_client_rekey_final);
 
@@ -54,24 +53,28 @@ SilcClient silc_client_alloc(SilcClientOperations *ops,
 
   new_client = silc_calloc(1, sizeof(*new_client));
   new_client->application = application;
-  new_client->ops = ops;
-  new_client->silc_client_version = strdup(silc_version);
-  new_client->params = silc_calloc(1, sizeof(*new_client->params));
+
+  new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
+  new_client->internal->ops = ops;
+  new_client->internal->params = 
+    silc_calloc(1, sizeof(*new_client->internal->params));
+  new_client->internal->silc_client_version = strdup(silc_version);
 
   if (params)
-    memcpy(new_client->params, params, sizeof(*params));
+    memcpy(new_client->internal->params, params, sizeof(*params));
 
-  if (!new_client->params->task_max)
-    new_client->params->task_max = 200;
+  if (!new_client->internal->params->task_max)
+    new_client->internal->params->task_max = 200;
 
-  if (!new_client->params->rekey_secs)
-    new_client->params->rekey_secs = 3600;
+  if (!new_client->internal->params->rekey_secs)
+    new_client->internal->params->rekey_secs = 3600;
 
-  if (!new_client->params->connauth_request_secs)
-    new_client->params->connauth_request_secs = 2;
+  if (!new_client->internal->params->connauth_request_secs)
+    new_client->internal->params->connauth_request_secs = 2;
 
-  new_client->params->
-    nickname_format[sizeof(new_client->params->nickname_format) - 1] = 0;
+  new_client->internal->params->
+    nickname_format[sizeof(new_client->internal->
+                          params->nickname_format) - 1] = 0;
 
   return new_client;
 }
@@ -84,8 +87,9 @@ void silc_client_free(SilcClient client)
     if (client->rng)
       silc_rng_free(client->rng);
 
-    silc_free(client->silc_client_version);
-    silc_free(client->params);
+    silc_free(client->internal->params);
+    silc_free(client->internal->silc_client_version);
+    silc_free(client->internal);
     silc_free(client);
   }
 }
@@ -99,11 +103,11 @@ int silc_client_init(SilcClient client)
   SILC_LOG_DEBUG(("Initializing client"));
 
   /* Initialize hash functions for client to use */
-  silc_hash_alloc("md5", &client->md5hash);
-  silc_hash_alloc("sha1", &client->sha1hash);
+  silc_hash_alloc("md5", &client->internal->md5hash);
+  silc_hash_alloc("sha1", &client->internal->sha1hash);
 
   /* Initialize none cipher */
-  silc_cipher_alloc("none", &client->none_cipher);
+  silc_cipher_alloc("none", &client->internal->none_cipher);
 
   /* Initialize random number generator */
   client->rng = silc_rng_alloc();
@@ -114,11 +118,15 @@ int silc_client_init(SilcClient client)
   silc_client_protocols_register();
 
   /* Initialize the scheduler */
-  client->schedule = silc_schedule_init(client->params->task_max ?
-                                       client->params->task_max : 200);
+  client->schedule = 
+    silc_schedule_init(client->internal->params->task_max ?
+                      client->internal->params->task_max : 200);
   if (!client->schedule)
     return FALSE;
 
+  /* Register commands */
+  silc_client_commands_register(client);
+
   return TRUE;
 }
 
@@ -133,6 +141,7 @@ void silc_client_stop(SilcClient client)
   silc_schedule_uninit(client->schedule);
 
   silc_client_protocols_unregister();
+  silc_client_commands_unregister(client);
 
   SILC_LOG_DEBUG(("Client stopped"));
 }
@@ -149,6 +158,20 @@ void silc_client_run(SilcClient client)
   silc_schedule(client->schedule);
 }
 
+/* Runs the client and returns immeadiately. This function is used when
+   the SILC Client object indicated by the `client' is run under some
+   other scheduler, or event loop or main loop.  On GUI applications,
+   for example this may be desired to use to run the client under the
+   GUI application's main loop.  Typically the GUI application would
+   register an idle task that calls this function multiple times in
+   a second to quickly process the SILC specific data. */
+
+void silc_client_run_one(SilcClient client)
+{
+  /* Run the scheduler once. */
+  silc_schedule_one(client->schedule, 0);
+}
+
 static void silc_client_entry_destructor(SilcIDCache cache,
                                         SilcIDCacheEntry entry)
 {
@@ -186,16 +209,17 @@ SilcClientConnection silc_client_add_connection(SilcClient client,
   conn->ftp_sessions = silc_dlist_init();
 
   /* Add the connection to connections table */
-  for (i = 0; i < client->conns_count; i++)
-    if (client->conns && !client->conns[i]) {
-      client->conns[i] = conn;
+  for (i = 0; i < client->internal->conns_count; i++)
+    if (client->internal->conns && !client->internal->conns[i]) {
+      client->internal->conns[i] = conn;
       return conn;
     }
 
-  client->conns = silc_realloc(client->conns, sizeof(*client->conns)
-                              * (client->conns_count + 1));
-  client->conns[client->conns_count] = conn;
-  client->conns_count++;
+  client->internal->conns = 
+    silc_realloc(client->internal->conns, sizeof(*client->internal->conns)
+                * (client->internal->conns_count + 1));
+  client->internal->conns[client->internal->conns_count] = conn;
+  client->internal->conns_count++;
 
   return conn;
 }
@@ -206,8 +230,8 @@ void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
 {
   int i;
 
-  for (i = 0; i < client->conns_count; i++)
-    if (client->conns[i] == conn) {
+  for (i = 0; i < client->internal->conns_count; i++)
+    if (client->internal->conns[i] == conn) {
 
       silc_idcache_free(conn->client_cache);
       silc_idcache_free(conn->channel_cache);
@@ -218,7 +242,7 @@ void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
       silc_dlist_uninit(conn->ftp_sessions);
       silc_free(conn);
 
-      client->conns[i] = NULL;
+      client->internal->conns[i] = NULL;
     }
 }
 
@@ -230,24 +254,28 @@ void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
 {
   int i;
 
-  if (!client->sockets) {
-    client->sockets = silc_calloc(1, sizeof(*client->sockets));
-    client->sockets[0] = silc_socket_dup(sock);
-    client->sockets_count = 1;
+  if (!client->internal->sockets) {
+    client->internal->sockets = 
+      silc_calloc(1, sizeof(*client->internal->sockets));
+    client->internal->sockets[0] = silc_socket_dup(sock);
+    client->internal->sockets_count = 1;
     return;
   }
 
-  for (i = 0; i < client->sockets_count; i++) {
-    if (client->sockets[i] == NULL) {
-      client->sockets[i] = silc_socket_dup(sock);
+  for (i = 0; i < client->internal->sockets_count; i++) {
+    if (client->internal->sockets[i] == NULL) {
+      client->internal->sockets[i] = silc_socket_dup(sock);
       return;
     }
   }
 
-  client->sockets = silc_realloc(client->sockets, sizeof(*client->sockets) *
-                                (client->sockets_count + 1));
-  client->sockets[client->sockets_count] = silc_socket_dup(sock);
-  client->sockets_count++;
+  client->internal->sockets = 
+    silc_realloc(client->internal->sockets, 
+                sizeof(*client->internal->sockets) *
+                (client->internal->sockets_count + 1));
+  client->internal->sockets[client->internal->sockets_count] = 
+    silc_socket_dup(sock);
+  client->internal->sockets_count++;
 }
 
 /* Deletes listener socket from the listener sockets table. */
@@ -256,13 +284,13 @@ void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
 {
   int i;
 
-  if (!client->sockets)
+  if (!client->internal->sockets)
     return;
 
-  for (i = 0; i < client->sockets_count; i++) {
-    if (client->sockets[i] == sock) {
+  for (i = 0; i < client->internal->sockets_count; i++) {
+    if (client->internal->sockets[i] == sock) {
       silc_socket_free(sock);
-      client->sockets[i] = NULL;
+      client->internal->sockets[i] = NULL;
       return;
     }
   }
@@ -314,8 +342,8 @@ int silc_client_connect_to_server(SilcClient client, int port,
 
   conn = silc_client_add_connection(client, host, port, context);
 
-  client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
-                  "Connecting to port %d of server %s", port, host);
+  client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
+                            "Connecting to port %d of server %s", port, host);
 
   /* Allocate internal context for connection process. This is
      needed as we are doing async connecting. */
@@ -358,7 +386,7 @@ bool silc_client_start_key_exchange(SilcClient client,
   silc_schedule_task_del_by_fd(client->schedule, fd);
 
   conn->nickname = strdup(client->username);
-  conn->sock->hostname = conn->remote_host;
+  conn->sock->hostname = strdup(conn->remote_host);
   conn->sock->ip = strdup(conn->remote_host);
   conn->sock->port = conn->remote_port;
 
@@ -378,8 +406,8 @@ bool silc_client_start_key_exchange(SilcClient client,
                      &protocol, (void *)proto_ctx,
                      silc_client_connect_to_server_second);
   if (!protocol) {
-    client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
-                    "Error: Could not start key exchange protocol");
+    client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+                              "Error: Could not start key exchange protocol");
     return FALSE;
   }
   conn->sock->protocol = protocol;
@@ -398,6 +426,19 @@ bool silc_client_start_key_exchange(SilcClient client,
   return TRUE;
 }
 
+/* Callback called when error has occurred during connecting to the server.
+   The `connect' client operation will be called. */
+
+SILC_TASK_CALLBACK(silc_client_connect_failure)
+{
+  SilcClientKEInternalContext *ctx = 
+    (SilcClientKEInternalContext *)context;
+  SilcClient client = (SilcClient)ctx->client;
+
+  client->internal->ops->connect(client, ctx->sock->user_data, FALSE);
+  silc_free(ctx);
+}
+
 /* Start of the connection to the remote server. This is called after
    succesful TCP/IP connection has been established to the remote host. */
 
@@ -416,12 +457,12 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
   if (opt != 0) {
     if (ctx->tries < 2) {
       /* Connection failed but lets try again */
-      client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
-                      "Could not connect to server %s: %s",
-                      ctx->host, strerror(opt));
-      client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
-                      "Connecting to port %d of server %s resumed", 
-                      ctx->port, ctx->host);
+      client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+                                "Could not connect to server %s: %s",
+                                ctx->host, strerror(opt));
+      client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
+                                "Connecting to port %d of server %s resumed", 
+                                ctx->port, ctx->host);
 
       /* Unregister old connection try */
       silc_schedule_unset_listen_fd(client->schedule, fd);
@@ -433,16 +474,16 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
       ctx->tries++;
     } else {
       /* Connection failed and we won't try anymore */
-      client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
-                      "Could not connect to server %s: %s",
-                      ctx->host, strerror(opt));
+      client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+                                "Could not connect to server %s: %s",
+                                ctx->host, strerror(opt));
       silc_schedule_unset_listen_fd(client->schedule, fd);
       silc_net_close_connection(fd);
       silc_schedule_task_del(client->schedule, ctx->task);
       silc_free(ctx);
 
       /* Notify application of failure */
-      client->ops->connect(client, conn, FALSE);
+      client->internal->ops->connect(client, conn, FALSE);
       silc_client_del_connection(client, conn);
     }
     return;
@@ -454,7 +495,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
 
   if (!silc_client_start_key_exchange(client, conn, fd)) {
     silc_net_close_connection(fd);
-    client->ops->connect(client, conn, FALSE);
+    client->internal->ops->connect(client, conn, FALSE);
   }
 }
 
@@ -486,8 +527,9 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
     silc_socket_free(ctx->sock);
 
     /* Notify application of failure */
-    client->ops->connect(client, ctx->sock->user_data, FALSE);
-    silc_free(ctx);
+    silc_schedule_task_add(client->schedule, ctx->sock->sock,
+                          silc_client_connect_failure, ctx,
+                          0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
     return;
   }
 
@@ -522,15 +564,17 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
   /* Resolve the authentication method to be used in this connection. The
      completion callback is called after the application has resolved
      the authentication method. */
-  client->ops->get_auth_method(client, sock->user_data, sock->hostname,
-                              sock->port, silc_client_resolve_auth_method,
-                              proto_ctx);
+  client->internal->ops->get_auth_method(client, sock->user_data, 
+                                        sock->hostname,
+                                        sock->port, 
+                                        silc_client_resolve_auth_method,
+                                        proto_ctx);
 }
 
 /* Authentication method resolving callback. Application calls this function
-   after we've called the client->ops->get_auth_method client operation
-   to resolve the authentication method. We will continue the executiong
-   of the protocol in this function. */
+   after we've called the client->internal->ops->get_auth_method 
+   client operation to resolve the authentication method. We will continue
+   the executiong of the protocol in this function. */
 
 void silc_client_resolve_auth_method(bool success,
                                     SilcProtocolAuthMeth auth_meth,
@@ -592,8 +636,9 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
     silc_socket_free(ctx->sock);
 
     /* Notify application of failure */
-    client->ops->connect(client, ctx->sock->user_data, FALSE);
-    silc_free(ctx);
+    silc_schedule_task_add(client->schedule, ctx->sock->sock,
+                          silc_client_connect_failure, ctx,
+                          0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
     return;
   }
 
@@ -624,7 +669,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
   conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
 
   /* Register re-key timeout */
-  conn->rekey->timeout = client->params->rekey_secs;
+  conn->rekey->timeout = client->internal->params->rekey_secs;
   conn->rekey->context = (void *)client;
   silc_schedule_task_add(client->schedule, conn->sock->sock, 
                         silc_client_rekey_callback,
@@ -743,14 +788,14 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
         close the connection */
       if (SILC_IS_DISCONNECTING(sock)) {
        if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
-         client->ops->disconnect(client, conn);
+         client->internal->ops->disconnect(client, conn);
        silc_client_close_connection(client, sock, conn);
        return;
       }
       
       SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
       if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
-       client->ops->disconnect(client, conn);
+       client->internal->ops->disconnect(client, conn);
       silc_client_close_connection(client, sock, conn);
       return;
     }
@@ -767,37 +812,6 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
   }
 }
 
-/* Parses whole packet, received earlier. */
-
-SILC_TASK_CALLBACK(silc_client_packet_parse_real)
-{
-  SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
-  SilcClient client = (SilcClient)parse_ctx->context;
-  SilcPacketContext *packet = parse_ctx->packet;
-  SilcSocketConnection sock = parse_ctx->sock;
-  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
-  int ret;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  /* Parse the packet */
-  if (parse_ctx->normal)
-    ret = silc_packet_parse(packet, conn->receive_key);
-  else
-    ret = silc_packet_parse_special(packet, conn->receive_key);
-
-  if (ret == SILC_PACKET_NONE)
-    goto out;
-
-  /* Parse the incoming packet type */
-  silc_client_packet_parse_type(client, sock, packet);
-
- out:
-  /*  silc_buffer_clear(sock->inbuf); */
-  silc_packet_context_free(packet);
-  silc_free(parse_ctx);
-}
-
 /* Parser callback called by silc_packet_receive_process. Thie merely
    registers timeout that will handle the actual parsing when appropriate. */
 
@@ -807,22 +821,40 @@ static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
   SilcClient client = (SilcClient)context;
   SilcSocketConnection sock = parser_context->sock;
   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+  SilcPacketContext *packet = parser_context->packet;
+  SilcPacketType ret;
 
-  if (conn && conn->hmac_receive)
+  if (conn && conn->hmac_receive && conn->sock == sock)
     conn->psn_receive = parser_context->packet->sequence + 1;
 
+  /* Parse the packet immediately */
+  if (parser_context->normal)
+    ret = silc_packet_parse(packet, conn->receive_key);
+  else
+    ret = silc_packet_parse_special(packet, conn->receive_key);
+
+  if (ret == SILC_PACKET_NONE) {
+    silc_packet_context_free(packet);
+    silc_free(parser_context);
+    return FALSE;
+  }
+  
   /* If protocol for this connection is key exchange or rekey then we'll
      process all packets synchronously, since there might be packets in
      queue that we are not able to decrypt without first processing the
      packets before them. */
-  if (sock->protocol && sock->protocol->protocol && 
-      (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
-       sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
-    silc_client_packet_parse_real(client->schedule, 0, sock->sock,
-                                 parser_context);
+  if ((ret == SILC_PACKET_REKEY || ret == SILC_PACKET_REKEY_DONE) ||
+      (sock->protocol && sock->protocol->protocol && 
+       (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
+       sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY))) {
+
+    /* Parse the incoming packet type */
+    silc_client_packet_parse_type(client, sock, packet);
+    silc_packet_context_free(packet);
+    silc_free(parser_context);
 
     /* Reprocess the buffer since we'll return FALSE. This is because
-       the `conn->receive_key' might have become valid bu processing
+       the `conn->receive_key' might have become valid by processing
        the previous packet */
     if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
       silc_packet_receive_process(sock, FALSE, conn->receive_key, 
@@ -831,16 +863,14 @@ static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
     else
       silc_packet_receive_process(sock, FALSE, NULL, NULL, 0, 
                                  silc_client_packet_parse, client);
+    
     return FALSE;
   }
 
-  /* Parse the packet */
-  silc_schedule_task_add(client->schedule, sock->sock, 
-                        silc_client_packet_parse_real,
-                        (void *)parser_context, 0, 1, 
-                        SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
-
+  /* Parse the incoming packet type */
+  silc_client_packet_parse_type(client, sock, packet);
+  silc_packet_context_free(packet);
+  silc_free(parser_context);
   return TRUE;
 }
 
@@ -1037,7 +1067,7 @@ void silc_client_packet_parse_type(SilcClient client,
        */
       SilcIDPayload idp;
 
-      idp = silc_id_payload_parse(buffer);
+      idp = silc_id_payload_parse(buffer->data, buffer->len);
       if (!idp)
        break;
       if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
@@ -1248,6 +1278,8 @@ void silc_client_close_connection(SilcClient client,
 {
   int del = FALSE;
 
+  SILC_LOG_DEBUG(("Start"));
+
   if (!sock || (sock && conn->sock == sock))
     del = TRUE;
   if (!sock)
@@ -1356,6 +1388,22 @@ void silc_client_close_connection(SilcClient client,
   silc_socket_free(sock);
 }
 
+/* Called when we receive disconnection packet from server. This 
+   closes our end properly and displays the reason of the disconnection
+   on the screen. */
+
+SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
+{
+  SilcClient client = (SilcClient)context;
+  SilcSocketConnection sock;
+
+  SILC_CLIENT_GET_SOCK(client, fd, sock);
+  if (sock == NULL)
+    return;
+
+  silc_client_close_connection(client, sock, sock->user_data);
+}
+
 /* Called when we receive disconnection packet from server. This 
    closes our end properly and displays the reason of the disconnection
    on the screen. */
@@ -1370,11 +1418,17 @@ void silc_client_disconnected_by_server(SilcClient client,
 
   msg = silc_calloc(message->len + 1, sizeof(char));
   memcpy(msg, message->data, message->len);
-  client->ops->say(client, sock->user_data, SILC_CLIENT_MESSAGE_AUDIT, msg);
+  client->internal->ops->say(client, sock->user_data, 
+                            SILC_CLIENT_MESSAGE_AUDIT, msg);
   silc_free(msg);
 
   SILC_SET_DISCONNECTED(sock);
-  silc_client_close_connection(client, sock, sock->user_data);
+
+  /* Close connection through scheduler. */
+  silc_schedule_task_add(client->schedule, sock->sock, 
+                        silc_client_disconnected_by_server_later,
+                        client, 0, 1, SILC_TASK_TIMEOUT, 
+                        SILC_TASK_PRI_NORMAL);
 }
 
 /* Received error message from server. Display it on the screen. 
@@ -1388,7 +1442,8 @@ void silc_client_error_by_server(SilcClient client,
 
   msg = silc_calloc(message->len + 1, sizeof(char));
   memcpy(msg, message->data, message->len);
-  client->ops->say(client, sock->user_data, SILC_CLIENT_MESSAGE_AUDIT, msg);
+  client->internal->ops->say(client, sock->user_data, 
+                            SILC_CLIENT_MESSAGE_AUDIT, msg);
   silc_free(msg);
 }
 
@@ -1401,6 +1456,7 @@ void silc_client_receive_new_id(SilcClient client,
 {
   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
   int connecting = FALSE;
+  SilcClientID *client_id = silc_id_payload_get_id(idp);
   SilcBuffer sidp;
 
   if (!conn->local_entry)
@@ -1408,6 +1464,12 @@ void silc_client_receive_new_id(SilcClient client,
 
   /* Delete old ID from ID cache */
   if (conn->local_id) {
+    /* Check whether they are different */
+    if (SILC_ID_CLIENT_COMPARE(conn->local_id, client_id)) {
+      silc_free(client_id);
+      return;
+    }
+
     silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
     silc_free(conn->local_id);
   }
@@ -1417,7 +1479,7 @@ void silc_client_receive_new_id(SilcClient client,
   if (conn->local_id_data)
     silc_free(conn->local_id_data);
 
-  conn->local_id = silc_id_payload_get_id(idp);
+  conn->local_id = client_id;
   conn->local_id_data = silc_id_payload_get_data(idp);
   conn->local_id_data_len = silc_id_payload_get_len(idp);;
 
@@ -1435,19 +1497,23 @@ void silc_client_receive_new_id(SilcClient client,
   
   /* Put it to the ID cache */
   silc_idcache_add(conn->client_cache, strdup(conn->nickname), conn->local_id, 
-                  (void *)conn->local_entry, FALSE);
-
-  /* Issue INFO command to fetch the real server name and server information
-     and other stuff. */
-  sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
-  silc_client_send_command(client, conn, SILC_COMMAND_INFO,
-                          ++conn->cmd_ident, 1, 2, sidp->data, sidp->len);
-  silc_buffer_free(sidp);
-
-  /* Notify application of successful connection. We do it here now that
-     we've received the Client ID and are allowed to send traffic. */
-  if (connecting)
-    client->ops->connect(client, conn, TRUE);
+                  (void *)conn->local_entry, 0, NULL);
+
+  if (connecting) {
+    /* Issue INFO comqmand to fetch the real server name and server information
+       and other stuff. */
+    silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
+                                silc_client_command_reply_info_i, 0, 
+                                ++conn->cmd_ident);
+    sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
+    silc_client_command_send(client, conn, SILC_COMMAND_INFO,
+                            conn->cmd_ident, 1, 2, sidp->data, sidp->len);
+    silc_buffer_free(sidp);
+
+    /* Notify application of successful connection. We do it here now that
+       we've received the Client ID and are allowed to send traffic. */
+    client->internal->ops->connect(client, conn, TRUE);
+  }
 }
 
 /* Processed received Channel ID for a channel. This is called when client
@@ -1474,7 +1540,7 @@ SilcChannelEntry silc_client_new_channel_id(SilcClient client,
 
   /* Put it to the ID cache */
   silc_idcache_add(conn->channel_cache, channel->channel_name, 
-                  (void *)channel->id, (void *)channel, FALSE);
+                  (void *)channel->id, (void *)channel, 0, NULL);
 
   return channel;
 }
@@ -1574,8 +1640,8 @@ void silc_client_process_failure(SilcClient client,
       SILC_GET32_MSB(failure, packet->buffer->data);
 
     /* Notify application */
-    client->ops->failure(client, sock->user_data, sock->protocol,
-                        (void *)failure);
+    client->internal->ops->failure(client, sock->user_data, sock->protocol,
+                                  (void *)failure);
   }
 }
 
@@ -1759,6 +1825,7 @@ silc_client_request_authentication_method(SilcClient client,
   connauth->timeout =
     silc_schedule_task_add(client->schedule, conn->sock->sock, 
                           silc_client_request_authentication_method_timeout,
-                          conn, client->params->connauth_request_secs, 0,
+                          conn, 
+                          client->internal->params->connauth_request_secs, 0,
                           SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 }