updtes
[silc.git] / lib / silcclient / client.c
index 64ecee8873b7e3d860c84280c2863bfdb9f63fe1..efcc29dad86fe5028a8f22e83f6bf0cbee3cde03 100644 (file)
@@ -186,10 +186,10 @@ static void silc_client_entry_destructor(SilcIDCache cache,
    application performed the connecting outside the library. The library
    however may use this internally. */
 
-SilcClientConnection silc_client_add_connection(SilcClient client,
-                                               char *hostname,
-                                               int port,
-                                               void *context)
+SilcClientConnection
+silc_client_add_connection(SilcClient client,
+                           SilcClientConnectionParams *params,
+                           char *hostname, int port, void *context)
 {
   SilcClientConnection conn;
   int i;
@@ -208,6 +208,13 @@ SilcClientConnection silc_client_add_connection(SilcClient client,
   conn->pending_commands = silc_dlist_init();
   conn->ftp_sessions = silc_dlist_init();
 
+  if (params) {
+    if (params->detach_data)
+      conn->params.detach_data = silc_memdup(params->detach_data,
+                                            params->detach_data_len);
+    conn->params.detach_data_len = params->detach_data_len;
+  }
+
   /* Add the connection to connections table */
   for (i = 0; i < client->internal->conns_count; i++)
     if (client->internal->conns && !client->internal->conns[i]) {
@@ -330,8 +337,9 @@ silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
    case then this function is not used at all. When the connecting is
    done the `connect' client operation is called. */
 
-int silc_client_connect_to_server(SilcClient client, int port,
-                                 char *host, void *context)
+int silc_client_connect_to_server(SilcClient client,
+                                  SilcClientConnectionParams *params,
+                                  int port, char *host, void *context)
 {
   SilcClientInternalConnectContext *ctx;
   SilcClientConnection conn;
@@ -340,7 +348,7 @@ int silc_client_connect_to_server(SilcClient client, int port,
   SILC_LOG_DEBUG(("Connecting to port %d of server %s",
                  port, host));
 
-  conn = silc_client_add_connection(client, host, port, context);
+  conn = silc_client_add_connection(client, params, host, port, context);
 
   client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
                             "Connecting to port %d of server %s", port, host);
@@ -806,14 +814,14 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
       if (SILC_IS_DISCONNECTING(sock)) {
        if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
          client->internal->ops->disconnect(client, conn);
-       silc_client_close_connection(client, sock, conn);
+       silc_client_close_connection_real(client, sock, conn);
        return;
       }
       
       SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
       if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
        client->internal->ops->disconnect(client, conn);
-      silc_client_close_connection(client, sock, conn);
+      silc_client_close_connection_real(client, sock, conn);
       return;
     }
 
@@ -1278,9 +1286,9 @@ void silc_client_packet_queue_purge(SilcClient client,
    connection but `conn->sock' might be actually a different connection
    than the `sock'). */
 
-void silc_client_close_connection(SilcClient client,
-                                 SilcSocketConnection sock,
-                                 SilcClientConnection conn)
+void silc_client_close_connection_real(SilcClient client,
+                                      SilcSocketConnection sock,
+                                      SilcClientConnection conn)
 {
   int del = FALSE;
 
@@ -1395,6 +1403,14 @@ void silc_client_close_connection(SilcClient client,
   silc_socket_free(sock);
 }
 
+/* Closes the connection to the remote end */
+
+void silc_client_close_connection(SilcClient client,
+                                 SilcClientConnection conn)
+{
+  silc_client_close_connection_real(client, NULL, conn);
+}
+
 /* Called when we receive disconnection packet from server. This 
    closes our end properly and displays the reason of the disconnection
    on the screen. */
@@ -1408,7 +1424,7 @@ SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
   if (sock == NULL)
     return;
 
-  silc_client_close_connection(client, sock, sock->user_data);
+  silc_client_close_connection_real(client, sock, sock->user_data);
 }
 
 /* Called when we receive disconnection packet from server. This 
@@ -1556,7 +1572,7 @@ void silc_client_remove_from_channels(SilcClient client,
   SilcChannelUser chu;
 
   silc_hash_table_list(client_entry->channels, &htl);
-  while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
+  while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
     silc_hash_table_del(chu->client->channels, chu->channel);
     silc_hash_table_del(chu->channel->user_list, chu->client);
     silc_free(chu);
@@ -1579,7 +1595,7 @@ void silc_client_replace_from_channels(SilcClient client,
   SilcChannelUser chu;
 
   silc_hash_table_list(old->channels, &htl);
-  while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
+  while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
     /* Replace client entry */
     silc_hash_table_del(chu->client->channels, chu->channel);
     silc_hash_table_del(chu->channel->user_list, chu->client);
@@ -1794,3 +1810,55 @@ silc_client_request_authentication_method(SilcClient client,
                           client->internal->params->connauth_request_secs, 0,
                           SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 }
+
+SilcBuffer silc_client_get_detach_data(SilcClient client,
+                                      SilcClientConnection conn)
+{
+  SilcBuffer detach;
+  SilcHashTableList htl;
+  SilcChannelUser chu;
+
+  SILC_LOG_DEBUG(("Creating detachment data"));
+
+  /* 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);
+  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_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_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;
+}