updates.
[silc.git] / lib / silcclient / client.c
index ed9bc13a9b200fd09be5387dcd4afa53ac0312a3..458a2fcd13110c97f33e4c65fa580054e4e0e181 100644 (file)
@@ -179,6 +179,51 @@ void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
     }
 }
 
+/* Adds listener socket to the listener sockets table. This function is
+   used to add socket objects that are listeners to the client.  This should
+   not be used to add other connection objects. */
+
+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] = sock;
+    client->sockets_count = 1;
+    return;
+  }
+
+  for (i = 0; i < client->sockets_count; i++) {
+    if (client->sockets[i] == NULL) {
+      client->sockets[i] = sock;
+      return;
+    }
+  }
+
+  client->sockets = silc_realloc(client->sockets, sizeof(*client->sockets) *
+                                (client->sockets_count + 1));
+  client->sockets[client->sockets_count] = sock;
+  client->sockets_count++;
+}
+
+/* Deletes listener socket from the listener sockets table. */
+
+void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
+{
+  int i;
+
+  if (!client->sockets)
+    return;
+
+  for (i = 0; i < client->sockets_count; i++) {
+    if (client->sockets[i] == sock) {
+      client->sockets[i] = NULL;
+      return;
+    }
+  }
+}
+
 static int 
 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
 {
@@ -419,18 +464,18 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
   if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
                                    sock->port, &proto_ctx->auth_meth,
                                    &proto_ctx->auth_data, 
-                                   &proto_ctx->auth_data_len))
-    {
-      /* XXX do AUTH_REQUEST resolcing with server */
-      proto_ctx->auth_meth = SILC_AUTH_NONE;
-    }
+                                   &proto_ctx->auth_data_len)) {
+    client->ops->say(client, ctx->sock->user_data, 
+                    "Could not resolve authentication method to use, "
+                    "assume no authentication");
+    proto_ctx->auth_meth = SILC_AUTH_NONE;
+  }
 
   /* Free old protocol as it is finished now */
   silc_protocol_free(protocol);
   if (ctx->packet)
     silc_packet_context_free(ctx->packet);
   silc_free(ctx);
-  /* silc_free(ctx->keymat....); */
   sock->protocol = NULL;
 
   /* Allocate the authentication protocol. This is allocated here
@@ -608,21 +653,27 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
       /* If connection is disconnecting already we will finally
         close the connection */
       if (SILC_IS_DISCONNECTING(sock)) {
-       client->ops->disconnect(client, conn);
-       silc_client_close_connection(client, conn);
+       if (sock == conn->sock)
+         client->ops->disconnect(client, conn);
+       silc_client_close_connection(client, sock, conn);
        return;
       }
       
       SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
-      client->ops->disconnect(client, conn);
-      silc_client_close_connection(client, conn);
+      if (sock == conn->sock)
+       client->ops->disconnect(client, conn);
+      silc_client_close_connection(client, sock, conn);
       return;
     }
 
     /* Process the packet. This will call the parser that will then
        decrypt and parse the packet. */
-    silc_packet_receive_process(sock, conn->receive_key, conn->hmac,
-                               silc_client_packet_parse, client);
+    if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
+      silc_packet_receive_process(sock, conn->receive_key, conn->hmac,
+                                 silc_client_packet_parse, client);
+    else
+      silc_packet_receive_process(sock, NULL, NULL,
+                                 silc_client_packet_parse, client);
   }
 }
 
@@ -643,9 +694,12 @@ static int silc_client_packet_decrypt_check(SilcPacketType packet_type,
 
      all other packets are special packets 
   */
-  if ((packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
-       !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) ||
-      packet_type != SILC_PACKET_CHANNEL_MESSAGE)
+
+  if (packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
+      (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
+    return FALSE;
+
+  if (packet_type != SILC_PACKET_CHANNEL_MESSAGE)
     return TRUE;
 
   return FALSE;
@@ -666,8 +720,13 @@ SILC_TASK_CALLBACK(silc_client_packet_parse_real)
   SILC_LOG_DEBUG(("Start"));
 
   /* Decrypt the received packet */
-  ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet,
-                           silc_client_packet_decrypt_check, parse_ctx);
+  if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
+    ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet,
+                             silc_client_packet_decrypt_check, parse_ctx);
+  else
+    ret = silc_packet_decrypt(NULL, NULL, buffer, packet,
+                             silc_client_packet_decrypt_check, parse_ctx);
+
   if (ret < 0)
     goto out;
 
@@ -687,7 +746,7 @@ SILC_TASK_CALLBACK(silc_client_packet_parse_real)
   silc_client_packet_parse_type(client, sock, packet);
 
  out:
-  silc_buffer_clear(sock->inbuf);
+  /*  silc_buffer_clear(sock->inbuf); */
   silc_packet_context_free(packet);
   silc_free(parse_ctx);
 }
@@ -795,7 +854,8 @@ void silc_client_packet_parse_type(SilcClient client,
     break;
 
   case SILC_PACKET_KEY_EXCHANGE:
-    if (sock->protocol) {
+    if (sock->protocol && sock->protocol->protocol && 
+       sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
       SilcClientKEInternalContext *proto_ctx = 
        (SilcClientKEInternalContext *)sock->protocol->context;
 
@@ -818,15 +878,32 @@ void silc_client_packet_parse_type(SilcClient client,
     break;
 
   case SILC_PACKET_KEY_EXCHANGE_1:
-    if (sock->protocol) {
+    if (sock->protocol && sock->protocol->protocol && 
+       sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
+      SilcClientKEInternalContext *proto_ctx = 
+       (SilcClientKEInternalContext *)sock->protocol->context;
+
+      if (proto_ctx->packet)
+       silc_packet_context_free(proto_ctx->packet);
+
+      proto_ctx->packet = silc_packet_context_dup(packet);
+      proto_ctx->dest_id_type = packet->src_id_type;
+      proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+                                         packet->src_id_type);
+      if (!proto_ctx->dest_id)
+       break;
 
+      /* Let the protocol handle the packet */
+      sock->protocol->execute(client->timeout_queue, 0,
+                             sock->protocol, sock->sock, 0, 0);
     } else {
       SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
                      "protocol active, packet dropped."));
     }
     break;
   case SILC_PACKET_KEY_EXCHANGE_2:
-    if (sock->protocol) {
+    if (sock->protocol && sock->protocol->protocol && 
+       sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
       SilcClientKEInternalContext *proto_ctx = 
        (SilcClientKEInternalContext *)sock->protocol->context;
 
@@ -929,7 +1006,8 @@ void silc_client_packet_send(SilcClient client,
   /* Set the packet context pointers */
   packetdata.flags = 0;
   packetdata.type = type;
-  if (((SilcClientConnection)sock->user_data)->local_id_data)
+  if (sock->user_data && 
+      ((SilcClientConnection)sock->user_data)->local_id_data)
     packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
   else 
     packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
@@ -979,12 +1057,23 @@ void silc_client_packet_send(SilcClient client,
 }
 
 /* Closes connection to remote end. Free's all allocated data except
-   for some information such as nickname etc. that are valid at all time. */
+   for some information such as nickname etc. that are valid at all time. 
+   If the `sock' is NULL then the conn->sock will be used.  If `sock' is
+   provided it will be checked whether the sock and `conn->sock' are the
+   same (they can be different, ie. a socket can use `conn' as its
+   connection but `conn->sock' might be actually a different connection
+   than the `sock'). */
 
 void silc_client_close_connection(SilcClient client,
+                                 SilcSocketConnection sock,
                                  SilcClientConnection conn)
 {
-  SilcSocketConnection sock = conn->sock;
+  int del = FALSE;
+
+  if (!sock || (sock && conn->sock == sock))
+    del = TRUE;
+  if (!sock)
+    sock = conn->sock;
 
   /* We won't listen for this connection anymore */
   silc_schedule_unset_listen_fd(sock->sock);
@@ -996,13 +1085,13 @@ void silc_client_close_connection(SilcClient client,
   /* Close the actual connection */
   silc_net_close_connection(sock->sock);
 
-  client->ops->say(client, sock->user_data,
-                  "Closed connection to host %s", sock->hostname);
-
   /* Free everything */
-  if (sock->user_data) {
+  if (del && sock->user_data) {
     /* XXX Free all client entries and channel entries. */
 
+    client->ops->say(client, sock->user_data,
+                    "Closed connection to host %s", sock->hostname);
+
     /* Clear ID caches */
     silc_idcache_del_all(conn->client_cache);
     silc_idcache_del_all(conn->channel_cache);
@@ -1069,7 +1158,7 @@ void silc_client_disconnected_by_server(SilcClient client,
   silc_free(msg);
 
   SILC_SET_DISCONNECTED(sock);
-  silc_client_close_connection(client, sock->user_data);
+  silc_client_close_connection(client, sock, sock->user_data);
 }
 
 /* Received error message from server. Display it on the screen. 
@@ -1128,8 +1217,9 @@ void silc_client_receive_new_id(SilcClient client,
   conn->local_entry->id = conn->local_id;
   
   /* Put it to the ID cache */
-  silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT,
-                  conn->local_id, (void *)conn->local_entry, TRUE, FALSE);
+  silc_idcache_add(conn->client_cache, conn->nickname, strlen(conn->nickname),
+                  SILC_ID_CLIENT, conn->local_id, (void *)conn->local_entry,
+                  TRUE, FALSE);
 
   /* Notify application of successful connection. We do it here now that
      we've received the Client ID and are allowed to send traffic. */
@@ -1161,8 +1251,9 @@ SilcChannelEntry silc_client_new_channel_id(SilcClient client,
   conn->current_channel = channel;
 
   /* Put it to the ID cache */
-  silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
-                  (void *)channel->id, (void *)channel, TRUE, FALSE);
+  silc_idcache_add(conn->channel_cache, channel_name, strlen(channel_name),
+                  SILC_ID_CHANNEL, (void *)channel->id, (void *)channel, 
+                  TRUE, FALSE);
 
   return channel;
 }
@@ -1252,9 +1343,9 @@ void silc_client_replace_from_channels(SilcClient client,
 
 /* Parses mode mask and returns the mode as string. */
 
-char *silc_client_chmode(unsigned int mode)
+char *silc_client_chmode(unsigned int mode, SilcChannelEntry channel)
 {
-  char string[20];
+  char string[100];
 
   if (!mode)
     return NULL;
@@ -1282,6 +1373,25 @@ char *silc_client_chmode(unsigned int mode)
   if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
     strncat(string, "a", 1);
 
+  if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
+    strncat(string, "f", 1);
+
+  if (mode & SILC_CHANNEL_MODE_CIPHER) {
+    char cipher[30];
+    memset(cipher, 0, sizeof(cipher));
+    snprintf(cipher, sizeof(cipher), " c (%s)", 
+            channel->channel_key->cipher->name);
+    strncat(string, cipher, strlen(cipher));
+  }
+
+  if (mode & SILC_CHANNEL_MODE_HMAC) {
+    char hmac[30];
+    memset(hmac, 0, sizeof(hmac));
+    snprintf(hmac, sizeof(hmac), " h (%s)", 
+            channel->hmac->hmac->name);
+    strncat(string, hmac, strlen(hmac));
+  }
+
   /* Rest of mode is ignored */
 
   return strdup(string);