Added support for UTF-8 encoded nicks, channel names and
authorPekka Riikonen <priikone@silcnet.org>
Thu, 31 Mar 2005 06:07:09 +0000 (06:07 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Thu, 31 Mar 2005 06:07:09 +0000 (06:07 +0000)
server names in client library.

CHANGES
lib/silcclient/client.c
lib/silcclient/client_notify.c
lib/silcclient/command.c
lib/silcclient/command_reply.c
lib/silcclient/idlist.c

diff --git a/CHANGES b/CHANGES
index c543fa5b3568ee3177ef5fe0f98cfa5cc3ddf9f1..12b4392e09cbd2ba50e9323cb6813daf6935d23f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,9 @@
+Thu Mar 31 08:52:06 EEST 2005  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added support for UTF-8 nicknames, channel names and
+         server names in client library.  Affected files in
+         lib/silcclient/.
+
 Wed Mar 30 22:16:35 EEST 2005  Pekka Riikonen <priikone@silcnet.org>
 
        * Added silc_utf8_str[n]casecmp into lib/silcutil/silcutf8.[ch].
index 33a975496864aadfe251a29323790ece27454dd4..d4546038895c4c10d7c0c85f9b1d234e72f609e5 100644 (file)
@@ -227,12 +227,6 @@ void silc_client_run_one(SilcClient client)
   silc_schedule_one(client->schedule, 0);
 }
 
-static void silc_client_entry_destructor(SilcIDCache cache,
-                                        SilcIDCacheEntry entry)
-{
-  silc_free(entry->name);
-}
-
 /* Allocates and adds new connection to the client. This adds the allocated
    connection to the connection table and returns a pointer to it. A client
    can have multiple connections to multiple servers. Every connection must
@@ -260,12 +254,11 @@ silc_client_add_connection(SilcClient client,
   conn->remote_port = port;
   conn->context = context;
   conn->internal->client_cache =
-    silc_idcache_alloc(0, SILC_ID_CLIENT, silc_client_entry_destructor,
-                      FALSE, FALSE);
+    silc_idcache_alloc(0, SILC_ID_CLIENT, NULL, FALSE, TRUE);
   conn->internal->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL,
-                                                    FALSE, FALSE);
+                                                    FALSE, TRUE);
   conn->internal->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL,
-                                                   FALSE, FALSE);
+                                                   FALSE, TRUE);
   conn->internal->pending_commands = silc_dlist_init();
   conn->internal->ftp_sessions = silc_dlist_init();
 
@@ -1745,6 +1738,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);
+  char *nickname;
 
   if (!conn->local_entry)
     connecting = TRUE;
@@ -1787,9 +1781,14 @@ void silc_client_receive_new_id(SilcClient client,
                                                        NULL, NULL, NULL,
                                                        TRUE);
 
-  /* Put it to the ID cache */
-  silc_idcache_add(conn->internal->client_cache,
-                  strdup(conn->nickname), conn->local_id,
+  /* Normalize nickname */
+  nickname = silc_identifier_check(conn->nickname, strlen(conn->nickname),
+                                  SILC_STRING_UTF8, 128, NULL);
+  if (!nickname)
+    return;
+
+    /* Put it to the ID cache */
+  silc_idcache_add(conn->internal->client_cache, nickname, conn->local_id,
                   (void *)conn->local_entry, 0, NULL);
 
   if (connecting) {
index a56d4b8b54702cb72154da9cc80527c61d39898c..eb1f97edb9d95bcb1bae370c21cbeba5946468a0 100644 (file)
@@ -634,11 +634,18 @@ void silc_client_notify_by_server(SilcClient client,
     if (SILC_ID_COMPARE_HASH(client_entry->id, client_id) &&
        silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
       /* Nickname didn't change.  Update only Client ID. */
+
+      /* Normalize nickname */
+      tmp = silc_identifier_check(tmp, strlen(tmp),
+                                 SILC_STRING_UTF8, 128, NULL);
+      if (!tmp)
+       goto out;
+
       silc_idcache_del_by_context(conn->internal->client_cache,
                                  client_entry);
       silc_free(client_entry->id);
       client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
-      silc_idcache_add(conn->internal->client_cache, strdup(tmp),
+      silc_idcache_add(conn->internal->client_cache, tmp,
                       client_entry->id, client_entry, 0, NULL);
 
       /* Notify application */
index a7f59aba217b56b2e92501b1855885e396b933c8..e2537fe69ca3b2a7a5daf0347e83ef4f63895531 100644 (file)
@@ -547,10 +547,8 @@ SILC_CLIENT_CMD_FUNC(list)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
-  SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry channel;
   SilcBuffer buffer, idp = NULL;
-  char *name;
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -559,14 +557,10 @@ SILC_CLIENT_CMD_FUNC(list)
   }
 
   if (cmd->argc == 2) {
-    name = cmd->argv[1];
-
     /* Get the Channel ID of the channel */
-    if (silc_idcache_find_by_name_one(conn->internal->channel_cache,
-                                     name, &id_cache)) {
-      channel = (SilcChannelEntry)id_cache->context;
-      idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
-    }
+    channel = silc_client_get_channel(cmd->client, cmd->conn, cmd->argv[1]);
+    if (channel)
+      idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
   }
 
   if (!idp)
@@ -597,7 +591,6 @@ SILC_CLIENT_CMD_FUNC(topic)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
-  SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry channel;
   SilcBuffer buffer, idp;
   char *name;
@@ -632,16 +625,14 @@ SILC_CLIENT_CMD_FUNC(topic)
   }
 
   /* Get the Channel ID of the channel */
-  if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
-                                    name, &id_cache)) {
+  channel = silc_client_get_channel(cmd->client, conn, name);
+  if (!channel) {
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
     goto out;
   }
 
-  channel = (SilcChannelEntry)id_cache->context;
-
   /* Send TOPIC command to the server */
-  idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
+  idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
   if (cmd->argc > 2)
     buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
                                            ++conn->cmd_ident, 2,
@@ -1971,7 +1962,6 @@ SILC_CLIENT_CMD_FUNC(kick)
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClient client = cmd->client;
   SilcClientConnection conn = cmd->conn;
-  SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry channel;
   SilcBuffer buffer, idp, idp2;
   SilcClientEntry target;
@@ -2007,14 +1997,12 @@ SILC_CLIENT_CMD_FUNC(kick)
   }
 
   /* Get the Channel ID of the channel */
-  if (!silc_idcache_find_by_name_one(conn->internal->channel_cache,
-                                    name, &id_cache)) {
+  channel = silc_client_get_channel(cmd->client, conn, name);
+  if (!channel) {
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL);
     goto out;
   }
 
-  channel = (SilcChannelEntry)id_cache->context;
-
   /* Parse the typed nickname. */
   if (client->internal->params->nickname_parse)
     client->internal->params->nickname_parse(cmd->argv[2], &nickname);
@@ -2032,7 +2020,7 @@ SILC_CLIENT_CMD_FUNC(kick)
   }
 
   /* Send KICK command to the server */
-  idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
+  idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
   idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
   if (cmd->argc == 3)
     buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK,
index 035f9f159ef1ffb572087dabe7478b496864f0e1..0c818a96988c18fa1706a3faee0502feb6c5cafa 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2004 Pekka Riikonen
+  Copyright (C) 1997 - 2005 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
@@ -580,9 +580,19 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick)
       silc_free(conn->nickname);
     conn->nickname = strdup(tmp);
     conn->local_entry->nickname = conn->nickname;
+
+    /* Normalize nickname */
+    tmp = silc_identifier_check(conn->nickname, strlen(conn->nickname),
+                               SILC_STRING_UTF8, 128, NULL);
+    if (!tmp) {
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_BAD_NICKNAME);
+      goto out;
+    }
+
     silc_client_nickname_format(cmd->client, conn, conn->local_entry);
-    silc_idcache_add(conn->internal->client_cache, strdup(tmp),
-                     conn->local_entry->id, conn->local_entry, 0, NULL);
+
+    silc_idcache_add(conn->internal->client_cache, tmp,
+                    conn->local_entry->id, conn->local_entry, 0, NULL);
   }
 
   /* Notify application */
index 8b69f6d48c7626bb1df9aeea323cac2e84ba7616..51cba4e3905e335cd41d660927a8afe15678b9b9 100644 (file)
@@ -48,18 +48,28 @@ SilcClientEntry *silc_client_get_clients_local(SilcClient client,
   SilcClientEntry entry, *clients;
   int i = 0;
   bool found = FALSE;
+  char *nicknamec;
 
   assert(client && conn);
   if (!nickname)
     return NULL;
 
+  /* Normalize nickname for search */
+  nicknamec = silc_identifier_check(nickname, strlen(nickname),
+                                   SILC_STRING_UTF8, 128, NULL);
+  if (!nicknamec)
+    return NULL;
+
   /* Find ID from cache */
-  if (!silc_idcache_find_by_name(conn->internal->client_cache,
-                                (char *)nickname, &list))
+  if (!silc_idcache_find_by_name(conn->internal->client_cache, nicknamec,
+                                &list)) {
+    silc_free(nicknamec);
     return NULL;
+  }
 
   if (!silc_idcache_list_count(list)) {
     silc_idcache_list_free(list);
+    silc_free(nicknamec);
     return NULL;
   }
 
@@ -95,6 +105,8 @@ SilcClientEntry *silc_client_get_clients_local(SilcClient client,
     }
   }
 
+  silc_free(nicknamec);
+
   if (list)
     silc_idcache_list_free(list);
 
@@ -381,12 +393,19 @@ SilcClientEntry silc_idlist_get_client(SilcClient client,
   SilcIDCacheEntry id_cache;
   SilcIDCacheList list = NULL;
   SilcClientEntry entry = NULL;
+  char *nicknamec;
 
   SILC_LOG_DEBUG(("Start"));
 
+  /* Normalize nickname for search */
+  nicknamec = silc_identifier_check(nickname, strlen(nickname),
+                                   SILC_STRING_UTF8, 128, NULL);
+  if (!nicknamec)
+    return NULL;
+
   /* Find ID from cache */
   if (!silc_idcache_find_by_name(conn->internal->client_cache,
-                                (char *)nickname, &list)) {
+                                nicknamec, &list)) {
   identify:
 
     if (query) {
@@ -405,8 +424,11 @@ SilcClientEntry silc_idlist_get_client(SilcClient client,
       if (list)
        silc_idcache_list_free(list);
 
+      silc_free(nicknamec);
       return NULL;
     }
+
+    silc_free(nicknamec);
     return NULL;
   }
 
@@ -440,6 +462,8 @@ SilcClientEntry silc_idlist_get_client(SilcClient client,
       goto identify;
   }
 
+  silc_free(nicknamec);
+
   if (list)
     silc_idcache_list_free(list);
 
@@ -954,12 +978,30 @@ silc_client_add_client(SilcClient client, SilcClientConnection conn,
   client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
                                                 NULL, NULL, NULL, TRUE);
 
+  /* Normalize nickname */
+  if (client_entry->nickname) {
+    silc_free(nick);
+    nick = silc_identifier_check(client_entry->nickname,
+                                strlen(client_entry->nickname),
+                                SILC_STRING_UTF8, 128, NULL);
+    if (!nick) {
+      silc_free(client_entry->nickname);
+      silc_free(client_entry->username);
+      silc_free(client_entry->hostname);
+      silc_free(client_entry->server);
+      silc_hash_table_free(client_entry->channels);
+      silc_free(client_entry);
+      return NULL;
+    }
+  }
+
   /* Format the nickname */
   silc_client_nickname_format(client, conn, client_entry);
 
   /* Add client to cache, the non-formatted nickname is saved to cache */
   if (!silc_idcache_add(conn->internal->client_cache, nick, client_entry->id,
                        (void *)client_entry, 0, NULL)) {
+    silc_free(nick);
     silc_free(client_entry->nickname);
     silc_free(client_entry->username);
     silc_free(client_entry->hostname);
@@ -999,6 +1041,16 @@ void silc_client_update_client(SilcClient client,
   if (!client_entry->nickname && nickname) {
     silc_parse_userfqdn(nickname, &nick, &client_entry->server);
     client_entry->nickname = strdup(nick);
+
+    /* Normalize nickname */
+    silc_free(nick);
+    nick = silc_identifier_check(client_entry->nickname,
+                                strlen(client_entry->nickname),
+                                SILC_STRING_UTF8, 128, NULL);
+    if (!nick)
+      return;
+
+    /* Format nickname */
     silc_client_nickname_format(client, conn, client_entry);
   }
   client_entry->mode = mode;
@@ -1068,6 +1120,7 @@ SilcChannelEntry silc_client_add_channel(SilcClient client,
                                         SilcChannelID *channel_id)
 {
   SilcChannelEntry channel;
+  char *channel_namec;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1078,9 +1131,20 @@ SilcChannelEntry silc_client_add_channel(SilcClient client,
   channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
                                             NULL, NULL, NULL, TRUE);
 
+  /* Normalize channel name */
+  channel_namec = silc_identifier_check(channel_name, strlen(channel_name),
+                                       SILC_STRING_UTF8, 256, NULL);
+  if (!channel_namec) {
+    silc_free(channel->channel_name);
+    silc_hash_table_free(channel->user_list);
+    silc_free(channel);
+    return NULL;
+  }
+
   /* Put it to the ID cache */
-  if (!silc_idcache_add(conn->internal->channel_cache, channel->channel_name,
+  if (!silc_idcache_add(conn->internal->channel_cache, channel_namec,
                        (void *)channel->id, (void *)channel, 0, NULL)) {
+    silc_free(channel_namec);
     silc_free(channel->channel_name);
     silc_hash_table_free(channel->user_list);
     silc_free(channel);
@@ -1161,6 +1225,8 @@ bool silc_client_replace_channel_id(SilcClient client,
                                    SilcChannelEntry channel,
                                    SilcChannelID *new_id)
 {
+  char *channel_namec;
+
   if (!new_id)
     return FALSE;
 
@@ -1172,8 +1238,15 @@ bool silc_client_replace_channel_id(SilcClient client,
   silc_idcache_del_by_id(conn->internal->channel_cache, channel->id);
   silc_free(channel->id);
   channel->id = new_id;
-  return silc_idcache_add(conn->internal->channel_cache,
-                         channel->channel_name,
+
+  /* Normalize channel name */
+  channel_namec = silc_identifier_check(channel->channel_name,
+                                       strlen(channel->channel_name),
+                                       SILC_STRING_UTF8, 256, NULL);
+  if (!channel_namec)
+    return FALSE;
+
+  return silc_idcache_add(conn->internal->channel_cache, channel_namec,
                          (void *)channel->id, (void *)channel, 0, NULL);
 
 }
@@ -1195,14 +1268,24 @@ SilcChannelEntry silc_client_get_channel(SilcClient client,
 
   SILC_LOG_DEBUG(("Start"));
 
+  /* Normalize name for search */
+  channel = silc_identifier_check(channel, strlen(channel), SILC_STRING_UTF8,
+                                 256, NULL);
+  if (!channel)
+    return NULL;
+
   if (!silc_idcache_find_by_name_one(conn->internal->channel_cache, channel,
-                                    &id_cache))
+                                    &id_cache)) {
+    silc_free(channel);
     return NULL;
+  }
 
   entry = (SilcChannelEntry)id_cache->context;
 
   SILC_LOG_DEBUG(("Found"));
 
+  silc_free(channel);
+
   return entry;
 }
 
@@ -1373,12 +1456,22 @@ SilcServerEntry silc_client_get_server(SilcClient client,
 
   SILC_LOG_DEBUG(("Start"));
 
+  /* Normalize server name for search */
+  server_name = silc_identifier_check(server_name, strlen(server_name),
+                                     SILC_STRING_UTF8, 256, NULL);
+  if (!server_name)
+    return NULL;
+
   if (!silc_idcache_find_by_name_one(conn->internal->server_cache,
-                                    server_name, &id_cache))
+                                    server_name, &id_cache)) {
+    silc_free(server_name);
     return NULL;
+  }
 
   entry = (SilcServerEntry)id_cache->context;
 
+  silc_free(server_name);
+
   return entry;
 }
 
@@ -1415,6 +1508,7 @@ SilcServerEntry silc_client_add_server(SilcClient client,
                                       SilcServerID *server_id)
 {
   SilcServerEntry server_entry;
+  char *server_namec = NULL;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1428,10 +1522,23 @@ SilcServerEntry silc_client_add_server(SilcClient client,
   if (server_info)
     server_entry->server_info = strdup(server_info);
 
+  /* Normalize server name */
+  if (server_name) {
+    server_namec = silc_identifier_check(server_name, strlen(server_name),
+                                        SILC_STRING_UTF8, 256, NULL);
+    if (!server_namec) {
+      silc_free(server_entry->server_id);
+      silc_free(server_entry->server_name);
+      silc_free(server_entry->server_info);
+      silc_free(server_entry);
+      return NULL;
+    }
+  }
+
   /* Add server to cache */
-  if (!silc_idcache_add(conn->internal->server_cache,
-                       server_entry->server_name,
+  if (!silc_idcache_add(conn->internal->server_cache, server_namec,
                        server_entry->server_id, server_entry, 0, NULL)) {
+    silc_free(server_namec);
     silc_free(server_entry->server_id);
     silc_free(server_entry->server_name);
     silc_free(server_entry->server_info);
@@ -1463,6 +1570,8 @@ void silc_client_update_server(SilcClient client,
                               const char *server_name,
                               const char *server_info)
 {
+  char *server_namec = NULL;
+
   SILC_LOG_DEBUG(("Start"));
 
   if (server_name &&
@@ -1472,9 +1581,18 @@ void silc_client_update_server(SilcClient client,
     silc_idcache_del_by_context(conn->internal->server_cache, server_entry);
     silc_free(server_entry->server_name);
     server_entry->server_name = strdup(server_name);
-    silc_idcache_add(conn->internal->server_cache, server_entry->server_name,
-                    server_entry->server_id,
-                    server_entry, 0, NULL);
+
+    /* Normalize server name */
+    if (server_name) {
+      server_namec = silc_identifier_check(server_name, strlen(server_name),
+                                          SILC_STRING_UTF8, 256, NULL);
+      if (!server_namec)
+       return;
+
+      silc_idcache_add(conn->internal->server_cache, server_namec,
+                      server_entry->server_id,
+                      server_entry, 0, NULL);
+    }
   }
 
   if (server_info &&