More client library rewrites.
[silc.git] / lib / silcclient / client_entry.c
index ce3717aaf0cd98d68e49a7d6c9bbf9496ee3141f..b752743351bbe3aebcbcb0ba24e0c54fcd3dfd2f 100644 (file)
@@ -78,11 +78,12 @@ SilcDList silc_client_get_clients_local(SilcClient client,
   if (!client || !conn || !nickname)
     return NULL;
 
+  SILC_LOG_DEBUG(("Find clients by nickname %s", nickname));
+
   /* Normalize nickname for search */
   nicknamec = silc_identifier_check(nickname, strlen(nickname),
                                    SILC_STRING_UTF8, 128, NULL);
   if (!nicknamec)
-    silc_free(nicknamec);
     return NULL;
 
   clients = silc_dlist_init();
@@ -94,6 +95,7 @@ SilcDList silc_client_get_clients_local(SilcClient client,
   silc_mutex_lock(conn->internal->lock);
 
   /* Find from cache */
+  silc_list_init(list, struct SilcIDCacheEntryStruct, next);
   if (!silc_idcache_find_by_name(conn->internal->client_cache, nicknamec,
                                 &list)) {
     silc_mutex_unlock(conn->internal->lock);
@@ -186,12 +188,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 +202,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 +226,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 +235,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 +243,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 +409,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;
@@ -458,7 +463,7 @@ void silc_client_get_clients_by_list(SilcClient client,
 
       res_argv[res_argc] = client_id_list->data;
       res_argv_lens[res_argc] = idp_len;
-      res_argv_types[res_argc] = res_argc + 5;
+      res_argv_types[res_argc] = res_argc + 4;
       res_argc++;
     }
     silc_client_unref_client(client, conn, entry);
@@ -470,20 +475,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 +498,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
@@ -686,6 +694,7 @@ SilcClientEntry silc_client_add_client(SilcClient client,
   if (!client_entry)
     return NULL;
 
+  silc_atomic_init8(&client_entry->internal.refcnt, 0);
   client_entry->id = *id;
   client_entry->internal.valid = TRUE;
   client_entry->mode = mode;
@@ -738,6 +747,7 @@ SilcClientEntry silc_client_add_client(SilcClient client,
   client_entry->nickname_normalized = nick;
 
   silc_mutex_unlock(conn->internal->lock);
+  silc_client_ref_client(client, conn, client_entry);
 
   return client_entry;
 }
@@ -839,6 +849,9 @@ void silc_client_ref_client(SilcClient client, SilcClientConnection conn,
                            SilcClientEntry client_entry)
 {
   silc_atomic_add_int8(&client_entry->internal.refcnt, 1);
+  SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry,
+                 silc_atomic_get_int8(&client_entry->internal.refcnt) - 1,
+                 silc_atomic_get_int8(&client_entry->internal.refcnt)));
 }
 
 /* Release reference of client entry */
@@ -846,6 +859,10 @@ void silc_client_ref_client(SilcClient client, SilcClientConnection conn,
 void silc_client_unref_client(SilcClient client, SilcClientConnection conn,
                              SilcClientEntry client_entry)
 {
+  if (client_entry)
+    SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry,
+                   silc_atomic_get_int8(&client_entry->internal.refcnt),
+                   silc_atomic_get_int8(&client_entry->internal.refcnt) - 1));
   if (client_entry &&
       silc_atomic_sub_int8(&client_entry->internal.refcnt, 1) == 0)
     silc_client_del_client(client, conn, client_entry);
@@ -922,7 +939,7 @@ void silc_client_nickname_format(SilcClient client,
 
   memset(newnick, 0, sizeof(newnick));
   cp = client->internal->params->nickname_format;
-  while (*cp) {
+  while (cp && *cp) {
     if (*cp == '%') {
       cp++;
       continue;
@@ -1179,49 +1196,40 @@ 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;
   SilcBuffer idp;
   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 +1238,10 @@ 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 ***************************/
@@ -1258,6 +1263,7 @@ SilcChannelEntry silc_client_add_channel(SilcClient client,
   if (!channel)
     return NULL;
 
+  silc_atomic_init8(&channel->internal.refcnt, 0);
   channel->id = *channel_id;
   channel->mode = mode;
 
@@ -1285,6 +1291,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 +1300,13 @@ 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);
+  silc_client_ref_channel(client, conn, channel);
+
   return channel;
 }
 
@@ -1490,13 +1502,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 +1573,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 +1586,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 +1610,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 +1619,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 ***************************/
@@ -1634,6 +1649,7 @@ SilcServerEntry silc_client_add_server(SilcClient client,
   if (!server_entry || !server_id)
     return NULL;
 
+  silc_atomic_init8(&server_entry->internal.refcnt, 0);
   server_entry->id = *server_id;
   if (server_name)
     server_entry->server_name = strdup(server_name);
@@ -1666,6 +1682,7 @@ SilcServerEntry silc_client_add_server(SilcClient client,
   }
 
   silc_mutex_unlock(conn->internal->lock);
+  silc_client_ref_server(client, conn, server_entry);
 
   return server_entry;
 }