updates. silc.client.0.7.4
authorPekka Riikonen <priikone@silcnet.org>
Thu, 31 Jan 2002 20:30:24 +0000 (20:30 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Thu, 31 Jan 2002 20:30:24 +0000 (20:30 +0000)
22 files changed:
CHANGES
TODO
apps/irssi/src/silc/core/client_ops.c
apps/irssi/src/silc/core/silc-channels.c
apps/silcd/packet_receive.c
apps/silcd/packet_send.c
apps/silcd/server.c
apps/silcd/server_util.c
lib/silcclient/client.c
lib/silcclient/client_channel.c
lib/silcclient/client_internal.h
lib/silcclient/client_notify.c
lib/silcclient/client_prvmsg.c
lib/silcclient/command.c
lib/silcclient/command_reply.c
lib/silcclient/idlist.c
lib/silcclient/idlist.h
lib/silcclient/silcapi.h
lib/silcutil/silchashtable.c
lib/silcutil/silchashtable.h
win32/libsilc/libsilc.def
win32/libsilcclient/libsilcclient.def

diff --git a/CHANGES b/CHANGES
index 2b9eefd7caada4952782ebbd50b6c70be283cd23..ef1aca765f847284ad5e99a6904be200f859f5f7 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,32 @@
+Thu Jan 31 19:06:22 EET 2002  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added function silc_client_add_channel, 
+         silc_client_replace_channel_id, and removed functions
+         silc_client_new_channel_id and silc_idlist_get_channel_by_id
+         from client library.
+
+       * Added cross reference of the joined channels to the 
+         SilcClientEntry, and changed the SilcChannelEntry's
+         users list to SilcHashTable.  The affected files are
+         lib/silcclient/idlist.[ch].
+
+       * Fixed a bug in hash table tarversing.  While the hash table
+         is traversed with SilcHashTableList the table must not be
+         rehashed.  It is now guaranteed that auto rehashable tables
+         are not rehashed while tarversing the list.  Also defined that
+         silc_hash_table_rehash must not be called while tarversing
+         the table.  Added function silc_hash_table_list_reset that must
+         be called after the tarversing is over.  The affected files are
+         lib/silcutil/silchashtable.[ch].
+
+       * Changed all hash table traversing to call the new
+         silc_hash_table_list_reset in server and in client library.
+
+       * Added function silc_client_on_channel to return the 
+         SilcChannelUser entry if the specified client entry is joined
+         on the specified channel.  This is exported to application as
+         well.  Affected files lib/silcclient/client_channel.c, silcapi.h.
+
 Wed Jan 30 19:14:31 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Fixed founder regaining problem with JOIN command on normal
diff --git a/TODO b/TODO
index a7b0f3af946ff9e6bf70feffde57fcf4ea737615..a7f0353880d773f97e5d2eb23ea015b8e2c22ced 100644 (file)
--- a/TODO
+++ b/TODO
@@ -51,6 +51,11 @@ TODO/bugs In SILC Client Library
 TODO/bugs In SILC Server
 ========================
 
+ o If server send CUMODE_CHANGE notify (like setting founder) to router
+   and router does not have founder on channel (founder is left or there's
+   no founder on channel at all), the router will accept the server's
+   founder mode change, even though it perhaps should not do that.
+
  o Make the normal server save user counts with LIST command reply.
 
  o The router should check for validity of received notify packets from
index 448109ccaeb35dccba9c79e9ad07199440102e61..5ece98928c10e725fd1b5e8e801fdda75a62d75f 100644 (file)
@@ -94,17 +94,10 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
   
   nick = silc_nicklist_find(chanrec, sender);
   if (!nick) {
-    /* We didn't find client but it clearly exists, add it. It must be
-       found on the channel->clients list. */
-    SilcChannelUser chu;
-
-    silc_list_start(channel->clients);
-    while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
-      if (chu->client == sender) {
-       nick = silc_nicklist_insert(chanrec, chu, FALSE);
-       break;
-      }
-    }
+    /* We didn't find client but it clearly exists, add it. */
+    SilcChannelUser chu = silc_client_on_channel(channel, sender);
+    if (chu)
+      nick = silc_nicklist_insert(chanrec, chu, FALSE);
   }
 
   if (flags & SILC_MESSAGE_FLAG_ACTION)
@@ -295,6 +288,7 @@ static void silc_client_join_get_users(SilcClient client,
                                       void *context)
 {
   SilcChannelEntry channel = (SilcChannelEntry)context;
+  SilcHashTableList htl;
   SilcChannelUser chu;
   SILC_SERVER_REC *server = conn->context;
   SILC_CHANNEL_REC *chanrec;
@@ -308,14 +302,15 @@ static void silc_client_join_get_users(SilcClient client,
   if (chanrec == NULL)
     return;
 
-  silc_list_start(channel->clients);
-  while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+  silc_hash_table_list(channel->user_list, &htl);
+  while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
     if (!chu->client->nickname)
       continue;
     if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
       founder = chu->client;
     silc_nicklist_insert(chanrec, chu, FALSE);
   }
+  silc_hash_table_list_reset(&htl);
 
   ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
   nicklist_set_own(CHANNEL(chanrec), ownnick);
@@ -753,6 +748,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     
   case SILC_COMMAND_USERS: 
     {
+      SilcHashTableList htl;
       SilcChannelEntry channel;
       SilcChannelUser chu;
       
@@ -765,8 +761,8 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
                         MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
                         channel->channel_name);
 
-      silc_list_start(channel->clients);
-      while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+      silc_hash_table_list(channel->user_list, &htl);
+      while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
        SilcClientEntry e = chu->client;
        char stat[5], *mode;
 
@@ -791,6 +787,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        if (mode)
          silc_free(mode);
       }
+      silc_hash_table_list_reset(&htl);
     }
     break;
 
index 5e52a6bbe861439e36576db8a9f574259a9bfa77..fa50947d524c06187b2fe04d821043e89d3f6ca5 100644 (file)
@@ -151,14 +151,9 @@ static void event_join(SILC_SERVER_REC *server, va_list va)
   } else {
     chanrec = silc_channel_find_entry(server, channel);
     if (chanrec != NULL) {
-      SilcChannelUser user;
-
-      silc_list_start(chanrec->entry->clients);
-      while ((user = silc_list_get(chanrec->entry->clients)) != NULL)
-       if (user->client == client) {
-         nickrec = silc_nicklist_insert(chanrec, user, TRUE);
-         break;
-       }
+      SilcChannelUser chu = silc_client_on_channel(channel, client);
+      if (chu)
+       nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
     }
   }
 
index 442dd310a6e4bf9f6efc56b999bee58259aac059..d1f6db8a8c391041b24b8777f72288b2c8d3d338 100644 (file)
@@ -630,6 +630,7 @@ void silc_server_notify(SilcServer server,
          if (chl2) {
            chl2->mode = mode;
            silc_free(channel_id);
+           silc_hash_table_list_reset(&htl);
            goto out;
          }
        }
@@ -650,6 +651,7 @@ void silc_server_notify(SilcServer server,
          chl2 = chl;
        }
       }
+      silc_hash_table_list_reset(&htl);
       
       /* Send the same notify to the channel */
       if (!notify_sent)
index 0860b68e1ea6c357acca50d1f72e7eac19cf2742..2c8786c3a5ada9eafd45c8a1fb44ca8b75334be4 100644 (file)
@@ -661,6 +661,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
                                            force_send);
   }
 
+  silc_hash_table_list_reset(&htl);
   silc_free(routed);
   silc_free(packetdata.src_id);
   silc_free(packetdata.dst_id);
@@ -943,6 +944,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
                                            force_send);
   }
 
+  silc_hash_table_list_reset(&htl);
   silc_free(routed);
   silc_free(packetdata.src_id);
   silc_free(packetdata.dst_id);
@@ -981,6 +983,7 @@ void silc_server_packet_send_local_channel(SilcServer server,
                                   force_send);
     }
   }
+  silc_hash_table_list_reset(&htl);
 }
 
 /* Routine used to send (relay, route) private messages to some destination.
@@ -1613,8 +1616,10 @@ void silc_server_send_notify_on_channels(SilcServer server,
        sent_clients[sent_clients_count++] = c;
       }
     }
+    silc_hash_table_list_reset(&htl2);
   }
 
+  silc_hash_table_list_reset(&htl);
   silc_free(routed);
   silc_free(sent_clients);
   silc_free(packetdata.src_id);
index 091a943610a9ee7cf4e656df0b43145c9530d3e9..d033284d457599c0614e9386425bcbd3794b2d38 100644 (file)
@@ -2604,6 +2604,7 @@ void silc_server_remove_from_channels(SilcServer server,
          silc_hash_table_del(channel->user_list, chl2->client);
          silc_free(chl2);
        }
+       silc_hash_table_list_reset(&htl2);
        continue;
       }
 
@@ -2628,7 +2629,7 @@ void silc_server_remove_from_channels(SilcServer server,
     if (keygen && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
       /* Re-generate channel key */
       if (!silc_server_create_channel_key(server, channel, 0))
-       return;
+       goto out;
       
       /* Send the channel key to the channel. The key of course is not sent
         to the client who was removed from the channel. */
@@ -2638,6 +2639,8 @@ void silc_server_remove_from_channels(SilcServer server,
     }
   }
 
+ out:
+  silc_hash_table_list_reset(&htl);
   silc_buffer_free(clidp);
 }
 
@@ -2724,6 +2727,7 @@ int silc_server_remove_from_one_channel(SilcServer server,
        silc_hash_table_del(channel->user_list, chl2->client);
        silc_free(chl2);
       }
+      silc_hash_table_list_reset(&htl2);
       return FALSE;
     }
 
@@ -3005,7 +3009,7 @@ bool silc_server_create_channel_key(SilcServer server,
     channel->rekey->task = 
       silc_schedule_task_add(server->schedule, 0, 
                             silc_server_channel_key_rekey,
-                            (void *)channel->rekey, 36, 0,
+                            (void *)channel->rekey, 3600, 0,
                             SILC_TASK_TIMEOUT,
                             SILC_TASK_PRI_NORMAL);
   }
@@ -3117,7 +3121,7 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
     channel->rekey->task = 
       silc_schedule_task_add(server->schedule, 0, 
                             silc_server_channel_key_rekey,
-                            (void *)channel->rekey, 36, 0,
+                            (void *)channel->rekey, 3600, 0,
                             SILC_TASK_TIMEOUT,
                             SILC_TASK_PRI_NORMAL);
   }
@@ -3433,6 +3437,7 @@ void silc_server_announce_get_channel_users(SilcServer server,
 
     silc_buffer_free(clidp);
   }
+  silc_hash_table_list_reset(&htl);
   silc_buffer_free(chidp);
 }
 
@@ -3676,6 +3681,7 @@ void silc_server_get_users_on_channel(SilcServer server,
   silc_hash_table_list(channel->user_list, &htl);
   while (silc_hash_table_get(&htl, NULL, (void *)&chl))
     len += (silc_id_get_len(chl->client->id, SILC_ID_CLIENT) + 4);
+  silc_hash_table_list_reset(&htl);
 
   client_id_list = silc_buffer_alloc(len);
   client_mode_list = 
@@ -3697,6 +3703,7 @@ void silc_server_get_users_on_channel(SilcServer server,
 
     list_count++;
   }
+  silc_hash_table_list_reset(&htl);
   silc_buffer_push(client_id_list, 
                   client_id_list->data - client_id_list->head);
   silc_buffer_push(client_mode_list, 
@@ -3921,6 +3928,7 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
     silc_buffer_pull(buffer, len);
     silc_free(cid);
   }
+  silc_hash_table_list_reset(&htl);
 
   if (buffer)
     silc_buffer_push(buffer, buffer->data - buffer->head);
index ad856b4af076e828ed8b1c7c14a9a561247e261e..5c06bcd17f11abd582c0b083772f33e68f751a17 100644 (file)
@@ -105,6 +105,7 @@ static void silc_server_remove_clients_channels(SilcServer server,
          silc_hash_table_del(channel->user_list, chl2->client);
          silc_free(chl2);
        }
+       silc_hash_table_list_reset(&htl2);
        continue;
       }
 
@@ -121,6 +122,7 @@ static void silc_server_remove_clients_channels(SilcServer server,
     if (!silc_hash_table_find(channels, channel, NULL, NULL))
       silc_hash_table_add(channels, channel, channel);
   }
+  silc_hash_table_list_reset(&htl);
 
   silc_buffer_free(clidp);
 }
@@ -340,8 +342,11 @@ bool silc_server_remove_clients_by_server(SilcServer server,
      must re-generate the channel key. */
   silc_hash_table_list(channels, &htl);
   while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
-    if (!silc_server_create_channel_key(server, channel, 0))
+    if (!silc_server_create_channel_key(server, channel, 0)) {
+      silc_hash_table_list_reset(&htl);
+      silc_hash_table_free(channels);
       return FALSE;
+    }
 
     /* Do not send the channel key if private channel key mode is set */
     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
@@ -351,6 +356,7 @@ bool silc_server_remove_clients_by_server(SilcServer server,
                                 server->server_type == SILC_ROUTER ? 
                                 FALSE : !server->standalone);
   }
+  silc_hash_table_list_reset(&htl);
   silc_hash_table_free(channels);
 
   return TRUE;
@@ -699,9 +705,12 @@ bool silc_server_channel_has_global(SilcChannelEntry channel)
 
   silc_hash_table_list(channel->user_list, &htl);
   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
-    if (chl->client->router)
+    if (chl->client->router) {
+      silc_hash_table_list_reset(&htl);
       return TRUE;
+    }
   }
+  silc_hash_table_list_reset(&htl);
 
   return FALSE;
 }
@@ -716,9 +725,12 @@ bool silc_server_channel_has_local(SilcChannelEntry channel)
 
   silc_hash_table_list(channel->user_list, &htl);
   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
-    if (!chl->client->router)
+    if (!chl->client->router) {
+      silc_hash_table_list_reset(&htl);
       return TRUE;
+    }
   }
+  silc_hash_table_list_reset(&htl);
 
   return FALSE;
 }
index d5867f13c6e392c928cce6c2da5ed26741fc9d23..ddd1285283653f8c688ca5d3b01f22587ebe6c3b 100644 (file)
@@ -1516,7 +1516,10 @@ void silc_client_receive_new_id(SilcClient client,
   conn->local_entry->server = strdup(conn->remote_host);
   conn->local_entry->id = conn->local_id;
   conn->local_entry->valid = TRUE;
-  
+  conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, 
+                                                     NULL, NULL,
+                                                     NULL, NULL, NULL, TRUE);
+
   /* Put it to the ID cache */
   silc_idcache_add(conn->client_cache, strdup(conn->nickname), conn->local_id, 
                   (void *)conn->local_entry, 0, NULL);
@@ -1545,73 +1548,22 @@ void silc_client_receive_new_id(SilcClient client,
   }
 }
 
-/* Processed received Channel ID for a channel. This is called when client
-   joins to channel and server replies with channel ID. The ID is cached. 
-   Returns the created channel entry. This is also called when received
-   channel ID in for example USERS command reply that we do not have. */
-
-SilcChannelEntry silc_client_new_channel_id(SilcClient client,
-                                           SilcSocketConnection sock,
-                                           char *channel_name,
-                                           uint32 mode, 
-                                           SilcIDPayload idp)
-{
-  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
-  SilcChannelEntry channel;
-
-  SILC_LOG_DEBUG(("New channel ID"));
-
-  channel = silc_calloc(1, sizeof(*channel));
-  channel->channel_name = channel_name;
-  channel->id = silc_id_payload_get_id(idp);
-  channel->mode = mode;
-  silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
-
-  /* Put it to the ID cache */
-  silc_idcache_add(conn->channel_cache, channel->channel_name, 
-                  (void *)channel->id, (void *)channel, 0, NULL);
-
-  return channel;
-}
-
-/* Removes a client entry from all channel it has joined. This really is
-   a performance killer (client_entry should have pointers to channel 
-   entry list). */
+/* Removes a client entry from all channels it has joined. */
 
 void silc_client_remove_from_channels(SilcClient client,
                                      SilcClientConnection conn,
                                      SilcClientEntry client_entry)
 {
-  SilcIDCacheEntry id_cache;
-  SilcIDCacheList list;
-  SilcChannelEntry channel;
+  SilcHashTableList htl;
   SilcChannelUser chu;
 
-  if (!silc_idcache_get_all(conn->channel_cache, &list))
-    return;
-
-  silc_idcache_list_first(list, &id_cache);
-  channel = (SilcChannelEntry)id_cache->context;
-  
-  while (channel) {
-    
-    /* Remove client from channel */
-    silc_list_start(channel->clients);
-    while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
-      if (chu->client == client_entry) {
-       silc_list_del(channel->clients, chu);
-       silc_free(chu);
-       break;
-      }
-    }
-
-    if (!silc_idcache_list_next(list, &id_cache))
-      break;
-    
-    channel = (SilcChannelEntry)id_cache->context;
+  silc_hash_table_list(client_entry->channels, &htl);
+  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);
   }
-
-  silc_idcache_list_free(list);
+  silc_hash_table_list_reset(&htl);
 }
 
 /* Replaces `old' client entries from all channels to `new' client entry.
@@ -1624,35 +1576,20 @@ void silc_client_replace_from_channels(SilcClient client,
                                       SilcClientEntry old,
                                       SilcClientEntry new)
 {
-  SilcIDCacheEntry id_cache;
-  SilcIDCacheList list;
-  SilcChannelEntry channel;
+  SilcHashTableList htl;
   SilcChannelUser chu;
 
-  if (!silc_idcache_get_all(conn->channel_cache, &list))
-    return;
-
-  silc_idcache_list_first(list, &id_cache);
-  channel = (SilcChannelEntry)id_cache->context;
-  
-  while (channel) {
-    
+  silc_hash_table_list(old->channels, &htl);
+  while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
     /* Replace client entry */
-    silc_list_start(channel->clients);
-    while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
-      if (chu->client == old) {
-       chu->client = new;
-       break;
-      }
-    }
-
-    if (!silc_idcache_list_next(list, &id_cache))
-      break;
+    silc_hash_table_del(chu->client->channels, chu->channel);
+    silc_hash_table_del(chu->channel->user_list, chu->client);
     
-    channel = (SilcChannelEntry)id_cache->context;
+    chu->client = new;
+    silc_hash_table_add(chu->channel->user_list, chu->client, chu);
+    silc_hash_table_add(chu->client->channels, chu->channel, chu);
   }
-
-  silc_idcache_list_free(list);
+  silc_hash_table_list_reset(&htl);
 }
 
 /* Registers failure timeout to process the received failure packet
index 0f952373a55b747708aa10c6ea73b551526e5577..814dea43b6c03b942ea56fab22ddac58bbaf09fd 100644 (file)
@@ -170,15 +170,13 @@ static void silc_client_channel_message_cb(SilcClient client,
   SilcChannelClientResolve res = (SilcChannelClientResolve)context;
 
   if (clients_count == 1) {
-    SilcIDCacheEntry id_cache = NULL;
     SilcChannelEntry channel;
     unsigned char *message;
 
-    if (!silc_idcache_find_by_id_one(conn->channel_cache, res->channel_id, 
-                                    &id_cache))
+    channel = silc_client_get_channel_by_id(client, conn, res->channel_id);
+    if (!channel)
       goto out;
 
-    channel = (SilcChannelEntry)id_cache->context;
     message = silc_channel_message_get_data(res->payload, NULL);
     
     /* Pass the message to application */
@@ -207,10 +205,8 @@ void silc_client_channel_message(SilcClient client,
   SilcChannelMessagePayload payload = NULL;
   SilcChannelID *id = NULL;
   SilcChannelEntry channel;
-  SilcChannelUser chu;
-  SilcIDCacheEntry id_cache = NULL;
+  SilcClientEntry client_entry;
   SilcClientID *client_id = NULL;
-  bool found = FALSE;
   unsigned char *message;
 
   SILC_LOG_DEBUG(("Start"));
@@ -228,11 +224,10 @@ void silc_client_channel_message(SilcClient client,
     goto out;
 
   /* Find the channel entry from channels on this connection */
-  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id, &id_cache))
+  channel = silc_client_get_channel_by_id(client, conn, id);
+  if (!channel)
     goto out;
 
-  channel = (SilcChannelEntry)id_cache->context;
-
   /* If there is no channel private key then just decrypt the message 
      with the channel key. If private keys are set then just go through
      all private keys and check what decrypts correctly. */
@@ -274,16 +269,8 @@ void silc_client_channel_message(SilcClient client,
   }
 
   /* Find client entry */
-  silc_list_start(channel->clients);
-  while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
-    if (SILC_ID_CLIENT_COMPARE(chu->client->id, client_id) && 
-       chu->client->nickname) {
-      found = TRUE;
-      break;
-    }
-  }
-
-  if (!found) {
+  client_entry = silc_client_get_client_by_id(client, conn, client_id);
+  if (!client_entry || !client_entry->nickname) {
     /* Resolve the client info */
     SilcChannelClientResolve res = silc_calloc(1, sizeof(*res));
     res->payload = payload;
@@ -296,19 +283,22 @@ void silc_client_channel_message(SilcClient client,
     goto out;
   }
 
+  if (!silc_client_on_channel(channel, client_entry)) {
+    SILC_LOG_WARNING(("Received channel message from client not on channel"));
+    goto out;
+  }
+
   message = silc_channel_message_get_data(payload, NULL);
 
   /* Pass the message to application */
   client->internal->ops->channel_message(
-                                client, conn, chu->client, channel,
+                                client, conn, client_entry, channel,
                                 silc_channel_message_get_flags(payload),
                                 message);
 
  out:
-  if (id)
-    silc_free(id);
-  if (client_id)
-    silc_free(client_id);
+  silc_free(id);
+  silc_free(client_id);
   if (payload)
     silc_channel_message_payload_free(payload);
 }
@@ -334,14 +324,14 @@ SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
    receive Channel Key Payload and when we are processing JOIN command 
    reply. */
 
-void silc_client_save_channel_key(SilcClientConnection conn,
+void silc_client_save_channel_key(SilcClient client,
+                                 SilcClientConnection conn,
                                  SilcBuffer key_payload, 
                                  SilcChannelEntry channel)
 {
   unsigned char *id_string, *key, *cipher, *hmac, hash[32];
   uint32 tmp_len;
   SilcChannelID *id;
-  SilcIDCacheEntry id_cache = NULL;
   SilcChannelKeyPayload payload;
 
   payload = silc_channel_key_payload_parse(key_payload->data,
@@ -363,12 +353,9 @@ void silc_client_save_channel_key(SilcClientConnection conn,
 
   /* Find channel. */
   if (!channel) {
-    if (!silc_idcache_find_by_id_one(conn->channel_cache, 
-                                    (void *)id, &id_cache))
+    channel = silc_client_get_channel_by_id(client, conn, id);
+    if (!channel)
       goto out;
-    
-    /* Get channel entry */
-    channel = (SilcChannelEntry)id_cache->context;
   }
 
   hmac = (channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : 
@@ -382,11 +369,11 @@ void silc_client_save_channel_key(SilcClientConnection conn,
   if (channel->old_hmac)
     silc_hmac_free(channel->old_hmac);
   if (channel->rekey_task)
-    silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
+    silc_schedule_task_del(client->schedule, channel->rekey_task);
   channel->old_channel_key = channel->channel_key;
   channel->old_hmac = channel->hmac;
   channel->rekey_task = 
-    silc_schedule_task_add(conn->client->schedule, 0,
+    silc_schedule_task_add(client->schedule, 0,
                           silc_client_save_channel_key_rekey, channel,
                           10, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 
@@ -401,7 +388,7 @@ void silc_client_save_channel_key(SilcClientConnection conn,
   memcpy(channel->key, key, tmp_len);
 
   if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
-    conn->client->internal->ops->say(
+    client->internal->ops->say(
                           conn->client, conn, 
                           SILC_CLIENT_MESSAGE_AUDIT,
                           "Cannot talk to channel: unsupported cipher %s", 
@@ -437,7 +424,7 @@ void silc_client_receive_channel_key(SilcClient client,
   SILC_LOG_DEBUG(("Received key for channel"));
 
   /* Save the key */
-  silc_client_save_channel_key(sock->user_data, packet, NULL);
+  silc_client_save_channel_key(client, sock->user_data, packet, NULL);
 }
 
 /* Adds private key for channel. This may be set only if the channel's mode
@@ -659,3 +646,19 @@ void silc_client_free_channel_private_keys(SilcChannelPrivateKey *keys,
 {
   silc_free(keys);
 }
+
+/* Returns the SilcChannelUser entry if the `client_entry' is joined on the 
+   channel indicated by the `channel'. NULL if client is not joined on
+   the channel. */
+
+SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
+                                      SilcClientEntry client_entry)
+{
+  SilcChannelUser chu;
+
+  if (silc_hash_table_find(channel->user_list, client_entry, NULL, 
+                          (void *)&chu))
+    return chu;
+
+  return NULL;
+}
index f796cb108958ea1ca1395199d6e75f112d87b6cb..6471d8c01fe2da0bab0fdd9df84cee10746c39c7 100644 (file)
@@ -164,12 +164,8 @@ void silc_client_error_by_server(SilcClient client,
 void silc_client_receive_new_id(SilcClient client,
                                SilcSocketConnection sock,
                                SilcIDPayload idp);
-SilcChannelEntry silc_client_new_channel_id(SilcClient client,
-                                           SilcSocketConnection sock,
-                                           char *channel_name,
-                                           uint32 mode, 
-                                           SilcIDPayload idp);
-void silc_client_save_channel_key(SilcClientConnection conn,
+void silc_client_save_channel_key(SilcClient client,
+                                 SilcClientConnection conn,
                                  SilcBuffer key_payload, 
                                  SilcChannelEntry channel);
 void silc_client_receive_channel_key(SilcClient client,
index d2895494df7f8a7bed4a4ecfc17ea399e92f7334..360da04a75c4a6725f3b0c7f944736ac592ff3e8 100644 (file)
@@ -103,7 +103,6 @@ void silc_client_notify_by_server(SilcClient client,
   SilcChannelEntry channel;
   SilcChannelUser chu;
   SilcServerEntry server;
-  SilcIDCacheEntry id_cache = NULL;
   unsigned char *tmp;
   uint32 tmp_len, mode;
 
@@ -143,10 +142,7 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     /* Get the channel entry */
-    channel = NULL;
-    if (silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                   &id_cache))
-      channel = (SilcChannelEntry)id_cache->context;
+    channel = silc_client_get_channel_by_id(client, conn, channel_id);
 
     /* Get sender Client ID */
     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
@@ -222,17 +218,17 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     /* Get channel entry */
-    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                    &id_cache))
+    channel = silc_client_get_channel_by_id(client, conn, channel_id);
+    if (!channel)
       break;
 
-    channel = (SilcChannelEntry)id_cache->context;
-
-    /* Add client to channel */
-    if (client_entry != conn->local_entry) {
+    /* Join the client to channel */
+    if (!silc_client_on_channel(channel, client_entry)) {
       chu = silc_calloc(1, sizeof(*chu));
       chu->client = client_entry;
-      silc_list_add(channel->clients, chu);
+      chu->channel = channel;
+      silc_hash_table_add(channel->user_list, client_entry, chu);
+      silc_hash_table_add(client_entry->channels, channel, chu);
     }
 
     /* Notify application. The channel entry is sent last as this notify
@@ -269,20 +265,16 @@ void silc_client_notify_by_server(SilcClient client,
                                SILC_ID_CHANNEL);
     if (!channel_id)
       goto out;
-    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                &id_cache))
+    channel = silc_client_get_channel_by_id(client, conn, channel_id);
+    if (!channel)
       break;
 
-    channel = (SilcChannelEntry)id_cache->context;
-
     /* Remove client from channel */
-    silc_list_start(channel->clients);
-    while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
-      if (chu->client == client_entry) {
-       silc_list_del(channel->clients, chu);
-       silc_free(chu);
-       break;
-      }
+    chu = silc_client_on_channel(channel, client_entry);
+    if (chu) {
+      silc_hash_table_del(client_entry->channels, channel);
+      silc_hash_table_del(channel->user_list, client_entry);
+      silc_free(chu);
     }
 
     /* Notify application. The channel entry is sent last as this notify
@@ -406,12 +398,10 @@ void silc_client_notify_by_server(SilcClient client,
                                SILC_ID_CHANNEL);
     if (!channel_id)
       goto out;
-    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                &id_cache))
+    channel = silc_client_get_channel_by_id(client, conn, channel_id);
+    if (!channel)
       break;
 
-    channel = (SilcChannelEntry)id_cache->context;
-
     /* Notify application. The channel entry is sent last as this notify
        is for channel but application don't know it from the arguments
        sent by server. */
@@ -562,14 +552,12 @@ void silc_client_notify_by_server(SilcClient client,
       silc_id_payload_free(idp);
       goto out;
     }
-    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                    &id_cache)) {
+    channel = silc_client_get_channel_by_id(client, conn, channel_id);
+    if (!channel) {
       silc_id_payload_free(idp);
       goto out;
     }
 
-    channel = (SilcChannelEntry)id_cache->context;
-
     /* Save the new mode */
     channel->mode = mode;
 
@@ -652,20 +640,14 @@ void silc_client_notify_by_server(SilcClient client,
                                SILC_ID_CHANNEL);
     if (!channel_id)
       goto out;
-    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                &id_cache))
+    channel = silc_client_get_channel_by_id(client, conn, channel_id);
+    if (!channel)
       break;
 
-    channel = (SilcChannelEntry)id_cache->context;
-
     /* Save the mode */
-    silc_list_start(channel->clients);
-    while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
-      if (chu->client == client_entry) {
-       chu->mode = mode;
-       break;
-      }
-    }
+    chu = silc_client_on_channel(channel, client_entry);
+    if (chu)
+      chu->mode = mode;
 
     /* Notify application. The channel entry is sent last as this notify
        is for channel but application don't know it from the arguments
@@ -706,37 +688,24 @@ void silc_client_notify_by_server(SilcClient client,
     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
     if (!channel_id)
       goto out;
-    
-    /* Get the channel entry */
-    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                    &id_cache))
-      break;
-
-    channel = (SilcChannelEntry)id_cache->context;
-
-    SILC_LOG_DEBUG(("Old Channel ID id(%s)", 
-                   silc_id_render(channel->id, SILC_ID_CHANNEL)));
 
-    /* Remove the old channel entry */
-    silc_idcache_del_by_context(conn->channel_cache, channel);
+    /* Get the channel entry */
+    channel = silc_client_get_channel_by_id(client, conn, channel_id);
+    if (!channel)
+      goto out;
 
-    /* Free the old ID */
-    silc_free(channel->id);
+    silc_free(channel_id);
 
     /* Get the new ID */
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
     if (!tmp)
       goto out;
-    channel->id = silc_id_payload_parse_id(tmp, tmp_len);
-    if (!channel->id)
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!channel_id)
       goto out;
 
-    SILC_LOG_DEBUG(("New Channel ID id(%s)", 
-                   silc_id_render(channel->id, SILC_ID_CHANNEL)));
-
-    /* Add the channel entry again to ID cache */
-    silc_idcache_add(conn->channel_cache, channel->channel_name, 
-                    channel->id, channel, 0, NULL);
+    /* Replace the Channel ID */
+    silc_client_replace_channel_id(client, conn, channel, channel_id);
 
     /* Notify application */
     client->internal->ops->notify(client, conn, type, channel, channel);
@@ -768,12 +737,10 @@ void silc_client_notify_by_server(SilcClient client,
                                SILC_ID_CHANNEL);
     if (!channel_id)
       goto out;
-    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                    &id_cache))
+    channel = silc_client_get_channel_by_id(client, conn, channel_id);
+    if (!channel)
       break;
 
-    channel = (SilcChannelEntry)id_cache->context;
-
     /* Get the kicker */
     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
     if (!tmp)
index 45b785e211b495e111670542467775917a80b081..9dc862141099d1fa5172677136133e067fc63f66 100644 (file)
@@ -161,13 +161,11 @@ void silc_client_private_message(SilcClient client,
     goto out;
 
   /* Check whether we know this client already */
-  if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)remote_id, 
-                                      NULL, NULL, 
-                                      silc_hash_client_id_compare, NULL,
-                                      &id_cache) || 
+  remote_client = silc_client_get_client_by_id(client, conn, remote_id);
+  if (!remote_client ||
       ((SilcClientEntry)id_cache->context)->nickname == NULL) {
 
-    if (id_cache && id_cache->context) {
+    if (remote_client) {
       remote_client = (SilcClientEntry)id_cache->context;
       if (remote_client->status & SILC_CLIENT_STATUS_RESOLVING) {
        remote_client->status &= ~SILC_CLIENT_STATUS_RESOLVING;
@@ -183,8 +181,6 @@ void silc_client_private_message(SilcClient client,
     return;
   }
 
-  remote_client = (SilcClientEntry)id_cache->context;
-
   /* Parse the payload and decrypt it also if private message key is set */
   payload = silc_private_message_payload_parse(packet->buffer->data,
                                               packet->buffer->len,
index f91beae0dd1316bda8da09900d508787ba584b53..7c94838374a6167cca177d69a3af66e4dac7974e 100644 (file)
@@ -947,7 +947,7 @@ SILC_CLIENT_CMD_FUNC(join)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
-  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry channel;
   SilcBuffer buffer, idp, auth = NULL;
   char *name, *passphrase = NULL, *cipher = NULL, *hmac = NULL;
   int i;
@@ -964,12 +964,9 @@ SILC_CLIENT_CMD_FUNC(join)
   }
   
   /* See if we have joined to the requested channel already */
-  if (silc_idcache_find_by_name_one(conn->channel_cache, cmd->argv[1],
-                                   &id_cache)) {
-    SilcChannelEntry channel = (SilcChannelEntry)id_cache->context;
-    if (channel->on_channel)
-      goto out;
-  }
+  channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
+  if (channel && silc_client_on_channel(channel, conn->local_entry))
+    goto out;
 
   idp = silc_id_payload_encode(conn->local_id, SILC_ID_CLIENT);
 
@@ -1467,13 +1464,9 @@ SILC_CLIENT_CMD_FUNC(cumode)
   }
   
   /* Get the current mode */
-  silc_list_start(channel->clients);
-  while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
-    if (chu->client == client_entry) {
-      mode = chu->mode;
-      break;
-    }
-  }
+  chu = silc_client_on_channel(channel, client_entry);
+  if (chu)
+    mode = chu->mode;
 
   /* Are we adding or removing mode */
   if (cmd->argv[2][0] == '-')
@@ -1995,8 +1988,8 @@ SILC_CLIENT_CMD_FUNC(leave)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
-  SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry channel;
+  SilcChannelUser chu;
   SilcBuffer buffer, idp;
   char *name;
 
@@ -2025,19 +2018,25 @@ SILC_CLIENT_CMD_FUNC(leave)
     name = cmd->argv[1];
   }
 
-  /* Get the Channel ID of the channel */
-  if (!silc_idcache_find_by_name_one(conn->channel_cache, name, &id_cache)) {
+  /* Get the channel entry */
+  channel = silc_client_get_channel(cmd->client, conn, name);
+  if (!channel) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
        "You are not on that channel");
     COMMAND_ERROR;
     goto out;
   }
 
-  channel = (SilcChannelEntry)id_cache->context;
-  channel->on_channel = FALSE;
+  /* Remove us from channel */
+  chu = silc_client_on_channel(channel, conn->local_entry);
+  if (chu) {
+    silc_hash_table_del(chu->client->channels, chu->channel);
+    silc_hash_table_del(chu->channel->user_list, chu->client);
+    silc_free(chu);
+  }
 
   /* Send LEAVE 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);
   buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1, 
                                          1, idp->data, idp->len);
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
index 248a51d44fd807dc3e72f7fa5468bfa63a56219b..f565899481c881624f606b5d5833714659eee14c 100644 (file)
@@ -211,7 +211,6 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
 {
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   SilcClientID *client_id;
-  SilcIDCacheEntry id_cache = NULL;
   SilcClientEntry client_entry = NULL;
   int argc;
   uint32 len;
@@ -266,16 +265,13 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
   fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
 
   /* Check if we have this client cached already. */
-  if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id, 
-                                      NULL, NULL, 
-                                      silc_hash_client_id_compare, NULL,
-                                      &id_cache)) {
+  client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
+  if (!client_entry) {
     SILC_LOG_DEBUG(("Adding new client entry"));
     client_entry = 
       silc_client_add_client(cmd->client, conn, nickname, username, realname,
                             client_id, mode);
   } else {
-    client_entry = (SilcClientEntry)id_cache->context;
     silc_client_update_client(cmd->client, conn, client_entry, 
                              nickname, username, realname, mode);
     silc_free(client_id);
@@ -356,7 +352,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(whowas)
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   SilcCommandStatus status;
   SilcClientID *client_id;
-  SilcIDCacheEntry id_cache = NULL;
   SilcClientEntry client_entry = NULL;
   uint32 len;
   unsigned char *id_data;
@@ -378,11 +373,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(whowas)
   }
 
   /* Get the client entry, if exists */
-  if (silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id, 
-                                     NULL, NULL, 
-                                     silc_hash_client_id_compare, NULL,
-                                     &id_cache)) 
-    client_entry = (SilcClientEntry)id_cache->context;
+  client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
   silc_free(client_id);
 
   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
@@ -458,17 +449,13 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
     SILC_LOG_DEBUG(("Received client information"));
 
     /* Check if we have this client cached already. */
-    if (!silc_idcache_find_by_id_one_ext(conn->client_cache, 
-                                        (void *)client_id, 
-                                        NULL, NULL, 
-                                        silc_hash_client_id_compare, NULL,
-                                        &id_cache)) {
+    client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
+    if (!client_entry) {
       SILC_LOG_DEBUG(("Adding new client entry"));
       client_entry = 
        silc_client_add_client(cmd->client, conn, name, info, NULL,
                               silc_id_dup(client_id, id_type), 0);
     } else {
-      client_entry = (SilcClientEntry)id_cache->context;
       silc_client_update_client(cmd->client, conn, client_entry, 
                                name, info, NULL, 0);
     }
@@ -517,16 +504,15 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
     SILC_LOG_DEBUG(("Received channel information"));
 
     /* Check if we have this channel cached already. */
-    if (!silc_idcache_find_by_id_one(conn->channel_cache, 
-                                    (void *)channel_id, &id_cache)) {
+    channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
+    if (!channel_entry) {
       if (!name)
        break;
 
-      SILC_LOG_DEBUG(("Adding new channel entry"));
-      channel_entry = silc_client_new_channel_id(client, conn->sock, 
-                                                strdup(name), 0, idp);
-    } else {
-      channel_entry = (SilcChannelEntry)id_cache->context;
+      /* Add new channel entry */
+      channel_entry = silc_client_add_channel(client, conn, name, 0,
+                                             channel_id);
+      channel_id = NULL;
     }
 
     /* Notify application */
@@ -680,7 +666,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(topic)
   SilcCommandStatus status;
   SilcChannelEntry channel;
   SilcChannelID *channel_id = NULL;
-  SilcIDCacheEntry id_cache = NULL;
   unsigned char *tmp;
   char *topic;
   uint32 argc, len;
@@ -714,15 +699,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(topic)
     goto out;
 
   /* Get the channel entry */
-  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                  &id_cache)) {
+  channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
+  if (!channel) {
     silc_free(channel_id);
     COMMAND_REPLY_ERROR;
     goto out;
   }
   
-  channel = (SilcChannelEntry)id_cache->context;
-
   /* Notify application */
   COMMAND_REPLY((ARGS, channel, topic));
 
@@ -740,7 +723,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(invite)
   SilcCommandStatus status;
   SilcChannelEntry channel;
   SilcChannelID *channel_id;
-  SilcIDCacheEntry id_cache;
   unsigned char *tmp;
   uint32 len;
 
@@ -763,14 +745,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(invite)
     goto out;
 
   /* Get the channel entry */
-  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                  &id_cache)) {
+  channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
+  if (!channel) {
     silc_free(channel_id);
     COMMAND_REPLY_ERROR;
     goto out;
   }
-  
-  channel = (SilcChannelEntry)id_cache->context;
 
   /* Get the invite list */
   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
@@ -941,11 +921,10 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   SilcCommandStatus status;
-  SilcIDPayload idp = NULL;
   SilcChannelEntry channel;
-  SilcIDCacheEntry id_cache = NULL;
   SilcChannelUser chu;
-  uint32 argc, mode, len, list_count;
+  SilcChannelID *channel_id;
+  uint32 argc, mode = 0, len, list_count;
   char *topic, *tmp, *channel_name = NULL, *hmac;
   SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
   int i;
@@ -977,7 +956,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
     COMMAND_REPLY_ERROR;
     goto out;
   }
-  channel_name = strdup(tmp);
+  channel_name = tmp;
 
   /* Get Channel ID */
   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
@@ -985,13 +964,11 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "Cannot join channel: Bad reply packet");
     COMMAND_REPLY_ERROR;
-    silc_free(channel_name);
     goto out;
   }
-  idp = silc_id_payload_parse(tmp, len);
-  if (!idp) {
+  channel_id = silc_id_payload_parse_id(tmp, len);
+  if (!channel_id) {
     COMMAND_REPLY_ERROR;
-    silc_free(channel_name);
     goto out;
   }
 
@@ -999,8 +976,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
   tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
   if (tmp)
     SILC_GET32_MSB(mode, tmp);
-  else
-    mode = 0;
 
   /* Get channel key */
   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
@@ -1013,15 +988,16 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
   /* Get topic */
   topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
 
-  /* If we have the channel entry, remove it and create a new one */
+  /* Check whether we have this channel entry already. */
   channel = silc_client_get_channel(cmd->client, conn, channel_name);
-  if (channel)
-    silc_client_del_channel(cmd->client, conn, channel);
-
-  /* Save received Channel ID. This actually creates the channel */
-  channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name, 
-                                      mode, idp);
-  silc_id_payload_free(idp);
+  if (channel) {
+    if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
+      silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
+  } else {
+    /* Create new channel entry */
+    channel = silc_client_add_channel(cmd->client, conn, channel_name, 
+                                     mode, channel_id);
+  }
 
   conn->current_channel = channel;
 
@@ -1032,7 +1008,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, 
          "Cannot join channel: Unsupported HMAC `%s'", hmac);
       COMMAND_REPLY_ERROR;
-      silc_free(channel_name);
       goto out;
     }
   }
@@ -1079,27 +1054,23 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
     SILC_GET32_MSB(mode, client_mode_list->data);
 
     /* Check if we have this client cached already. */
-    if (!silc_idcache_find_by_id_one_ext(conn->client_cache, 
-                                        (void *)client_id, 
-                                        NULL, NULL, 
-                                        silc_hash_client_id_compare, NULL,
-                                        &id_cache)) {
+    client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
+    if (!client_entry) {
       /* No, we don't have it, add entry for it. */
       client_entry = 
        silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
                               silc_id_dup(client_id, SILC_ID_CLIENT), 0);
-    } else {
-      /* Yes, we have it already */
-      client_entry = (SilcClientEntry)id_cache->context;
     }
 
-    /* Join the client to the channel */
+    /* Join client to the channel */
     chu = silc_calloc(1, sizeof(*chu));
     chu->client = client_entry;
+    chu->channel = channel;
     chu->mode = mode;
-    silc_list_add(channel->clients, chu);
-    silc_free(client_id);
+    silc_hash_table_add(channel->user_list, client_entry, chu);
+    silc_hash_table_add(client_entry->channels, channel, chu);
 
+    silc_free(client_id);
     silc_buffer_pull(client_id_list, idp_len);
     silc_buffer_pull(client_mode_list, 4);
   }
@@ -1109,11 +1080,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
                   client_mode_list->head);
 
   /* Save channel key */
-  if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
-    silc_client_save_channel_key(conn, keyp, channel);
-
-  /* Client is now joined to the channel */
-  channel->on_channel = TRUE;
+  if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
+    silc_client_save_channel_key(cmd->client, conn, keyp, channel);
 
   /* Notify application */
   COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, 
@@ -1239,7 +1207,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode)
   SilcCommandStatus status;
   unsigned char *tmp;
   uint32 mode;
-  SilcIDCacheEntry id_cache;
   SilcChannelID *channel_id;
   SilcChannelEntry channel;
   uint32 len;
@@ -1261,15 +1228,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode)
     goto out;
 
   /* Get the channel entry */
-  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                  &id_cache)) {
+  channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
+  if (!channel) {
     silc_free(channel_id);
     COMMAND_REPLY_ERROR;
     goto out;
   }
   
-  channel = (SilcChannelEntry)id_cache->context;
-
   /* Get channel mode */
   tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
   if (!tmp) {
@@ -1299,7 +1264,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode)
   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   SilcCommandStatus status;
-  SilcIDCacheEntry id_cache = NULL;
   SilcClientID *client_id;
   SilcChannelID *channel_id;
   SilcClientEntry client_entry;
@@ -1332,15 +1296,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode)
     goto out;
 
   /* Get the channel entry */
-  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                  &id_cache)) {
+  channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
+  if (!channel) {
     silc_free(channel_id);
     COMMAND_REPLY_ERROR;
     goto out;
   }
   
-  channel = (SilcChannelEntry)id_cache->context;
-
   /* Get Client ID */
   id = silc_argument_get_arg_type(cmd->args, 4, &len);
   if (!id) {
@@ -1356,27 +1318,19 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode)
   }
   
   /* Get client entry */
-  if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id, 
-                                      NULL, NULL, 
-                                      silc_hash_client_id_compare, NULL,
-                                      &id_cache)) {
+  client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
+  if (!client_entry) {
     silc_free(channel_id);
     silc_free(client_id);
     COMMAND_REPLY_ERROR;
     goto out;
   }
 
-  client_entry = (SilcClientEntry)id_cache->context;
-
   /* Save the mode */
   SILC_GET32_MSB(mode, modev);
-  silc_list_start(channel->clients);
-  while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
-    if (chu->client == client_entry) {
-      chu->mode = mode;
-      break;
-    }
-  }
+  chu = silc_client_on_channel(channel, client_entry);
+  if (chu)
+    chu->mode = mode;
 
   /* Notify application */
   COMMAND_REPLY((ARGS, mode, channel, client_entry));
@@ -1489,7 +1443,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(ban)
   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   SilcCommandStatus status;
-  SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry channel;
   SilcChannelID *channel_id;
   unsigned char *tmp;
@@ -1514,15 +1467,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(ban)
     goto out;
 
   /* Get the channel entry */
-  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                  &id_cache)) {
+  channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
+  if (!channel) {
     silc_free(channel_id);
     COMMAND_REPLY_ERROR;
     goto out;
   }
   
-  channel = (SilcChannelEntry)id_cache->context;
-
   /* Get the ban list */
   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
 
@@ -1608,6 +1559,30 @@ SILC_CLIENT_CMD_REPLY_FUNC(leave)
   silc_client_command_reply_free(cmd);
 }
 
+/* Channel resolving callback for USERS command reply. */
+
+static void silc_client_command_reply_users_cb(SilcClient client,
+                                              SilcClientConnection conn,
+                                              SilcChannelEntry *channels,
+                                              uint32 channels_count,
+                                              void *context)
+{
+  if (!channels_count) {
+    SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+    SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+    SilcCommandStatus status = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
+
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+       "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
+    silc_client_command_reply_free(cmd);
+    return;
+  }
+
+  silc_client_command_reply_users(context, NULL);
+}
+
 /* Reply to USERS command. Received list of client ID's and theirs modes
    on the channel we requested. */
 
@@ -1616,8 +1591,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(users)
   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   SilcCommandStatus status;
-  SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry channel;
+  SilcClientEntry client_entry;
   SilcChannelUser chu;
   SilcChannelID *channel_id = NULL;
   SilcBuffer client_id_list = NULL;
@@ -1682,26 +1657,18 @@ SILC_CLIENT_CMD_REPLY_FUNC(users)
   silc_buffer_put(client_mode_list, tmp, tmp_len);
 
   /* Get channel entry */
-  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
-                                  &id_cache)) {
+  channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
+  if (!channel) {
     /* Resolve the channel from server */
-    silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
-    
-    /* Register pending command callback. After we've received the channel
-       information we will reprocess this command reply by re-calling this
-       USERS command reply callback. */
-    silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
-                               silc_client_command_reply_users, cmd);
+    silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
+                                         silc_client_command_reply_users_cb,
+                                         cmd);
+    silc_free(channel_id);
+    if (client_id_list)
+      silc_buffer_free(client_id_list);
+    if (client_mode_list)
+      silc_buffer_free(client_mode_list);
     return;
-  } else {
-    channel = (SilcChannelEntry)id_cache->context;
-  }
-
-  /* Remove old client list from channel. */
-  silc_list_start(channel->clients);
-  while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
-    silc_list_del(channel->clients, chu);
-    silc_free(chu);
   }
 
   /* Cache the received Client ID's and modes. */
@@ -1709,7 +1676,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(users)
     uint16 idp_len;
     uint32 mode;
     SilcClientID *client_id;
-    SilcClientEntry client;
 
     /* Client ID */
     SILC_GET16_MSB(idp_len, client_id_list->data + 2);
@@ -1722,18 +1688,9 @@ SILC_CLIENT_CMD_REPLY_FUNC(users)
     SILC_GET32_MSB(mode, client_mode_list->data);
 
     /* Check if we have this client cached already. */
-    id_cache = NULL;
-    silc_idcache_find_by_id_one_ext(conn->client_cache, 
-                                   (void *)client_id, 
-                                   NULL, NULL, 
-                                   silc_hash_client_id_compare, NULL,
-                                   &id_cache);
-
-    if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
-       !((SilcClientEntry)id_cache->context)->realname) {
-
-      if (id_cache && id_cache->context) {
-       SilcClientEntry client_entry = (SilcClientEntry)id_cache->context;
+    client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
+    if (!client_entry || !client_entry->username || !client_entry->realname) {
+      if (client_entry) {
        if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
          silc_buffer_pull(client_id_list, idp_len);
          silc_buffer_pull(client_mode_list, 4);
@@ -1756,17 +1713,16 @@ SILC_CLIENT_CMD_REPLY_FUNC(users)
       res_argv_types[res_argc] = res_argc + 3;
       res_argc++;
     } else {
-      /* Found the client, join it to the channel */
-      client = (SilcClientEntry)id_cache->context;
-      chu = silc_calloc(1, sizeof(*chu));
-      chu->client = client;
-      chu->mode = mode;
-      silc_list_add(channel->clients, chu);
-
-      silc_free(client_id);
-      id_cache = NULL;
+      if (!silc_client_on_channel(channel, client_entry)) {
+       chu = silc_calloc(1, sizeof(*chu));
+       chu->client = client_entry;
+       chu->channel = channel;
+       silc_hash_table_add(channel->user_list, client_entry, chu);
+       silc_hash_table_add(client_entry->channels, channel, chu);
+      }
     }
 
+    silc_free(client_id);
     silc_buffer_pull(client_id_list, idp_len);
     silc_buffer_pull(client_mode_list, 4);
   }
@@ -1794,14 +1750,21 @@ SILC_CLIENT_CMD_REPLY_FUNC(users)
                                silc_client_command_reply_users, cmd);
 
     silc_buffer_free(res_cmd);
-    if (channel_id)
-      silc_free(channel_id);
-
+    silc_free(channel_id);
     silc_free(res_argv);
     silc_free(res_argv_lens);
     silc_free(res_argv_types);
+    if (client_id_list)
+      silc_buffer_free(client_id_list);
+    if (client_mode_list)
+      silc_buffer_free(client_mode_list);
     return;
   }
+  
+  silc_buffer_push(client_id_list, (client_id_list->data - 
+                                   client_id_list->head));
+  silc_buffer_push(client_mode_list, (client_mode_list->data - 
+                                     client_mode_list->head));
 
   /* Notify application */
   COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
@@ -1876,17 +1839,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(getkey)
   if (id_type == SILC_ID_CLIENT) {
     /* Received client's public key */
     client_id = silc_id_payload_get_id(idp);
-    if (!silc_idcache_find_by_id_one_ext(conn->client_cache, 
-                                        (void *)client_id, 
-                                        NULL, NULL, 
-                                        silc_hash_client_id_compare, NULL,
-                                        &id_cache)) {
+    client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
+    if (!client_entry) {
       COMMAND_REPLY_ERROR;
       goto out;
     }
 
-    client_entry = (SilcClientEntry)id_cache->context;
-
     /* Notify application */
     COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
   } else if (id_type == SILC_ID_SERVER) {
index 0dd94e4ae9cc364d5c23bc20c4ad92733f047119..aa5ccc27f22e86c2a4355bd92bb54822f49625b4 100644 (file)
@@ -1,6 +1,6 @@
 /*
 
-  idlist.c
+  idlist.c 
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
@@ -8,9 +8,8 @@
 
   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
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
+  the Free Software Foundation; version 2 of the License.
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -586,6 +585,8 @@ silc_client_add_client(SilcClient client, SilcClientConnection conn,
   client_entry->mode = mode;
   if (nick)
     client_entry->nickname = strdup(nick);
+  client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
+                                                NULL, NULL, NULL, TRUE);
 
   /* Format the nickname */
   silc_client_nickname_format(client, conn, client_entry);
@@ -597,6 +598,7 @@ silc_client_add_client(SilcClient client, SilcClientConnection conn,
     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;
   }
@@ -653,6 +655,7 @@ void silc_client_del_client_entry(SilcClient client,
   silc_free(client_entry->server);
   silc_free(client_entry->id);
   silc_free(client_entry->fingerprint);
+  silc_hash_table_free(client_entry->channels);
   if (client_entry->send_key)
     silc_cipher_free(client_entry->send_key);
   if (client_entry->receive_key)
@@ -680,12 +683,65 @@ bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
   return ret;
 }
 
+/* Add new channel entry to the ID Cache */
+
+SilcChannelEntry silc_client_add_channel(SilcClient client,
+                                        SilcClientConnection conn,
+                                        const char *channel_name,
+                                        uint32 mode, 
+                                        SilcChannelID *channel_id)
+{
+  SilcChannelEntry channel;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  channel = silc_calloc(1, sizeof(*channel));
+  channel->channel_name = strdup(channel_name);
+  channel->id = channel_id;
+  channel->mode = mode;
+  channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL,
+                                            NULL, NULL, NULL, TRUE);
+
+  /* Put it to the ID cache */
+  if (!silc_idcache_add(conn->channel_cache, channel->channel_name, 
+                       (void *)channel->id, (void *)channel, 0, NULL)) {
+    silc_free(channel->channel_name);
+    silc_hash_table_free(channel->user_list);
+    silc_free(channel);
+    return NULL;
+  }
+
+  return channel;
+}
+
+/* Foreach callbcak to free all users from the channel when deleting a
+   channel entry. */
+
+static void silc_client_del_channel_foreach(void *key, void *context,
+                                           void *user_context)
+{
+  SilcChannelUser chu = (SilcChannelUser)context;
+
+  /* Remove the context from the client's channel hash table as that
+     table and channel's user_list hash table share this same context. */
+  silc_hash_table_del(chu->client->channels, chu->channel);
+  silc_free(chu);
+}
+
 /* Removes channel from the cache by the channel entry. */
 
 bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
                             SilcChannelEntry channel)
 {
   bool ret = silc_idcache_del_by_context(conn->channel_cache, channel);
+
+  /* Free all client entrys from the users list. The silc_hash_table_free
+     will free all the entries so they are not freed at the foreach 
+     callback. */
+  silc_hash_table_foreach(channel->user_list, silc_client_del_channel_foreach,
+                         NULL);
+  silc_hash_table_free(channel->user_list);
+
   silc_free(channel->channel_name);
   silc_free(channel->id);
   silc_free(channel->key);
@@ -704,6 +760,30 @@ bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
   return ret;
 }
 
+/* Replaces the channel ID of the `channel' to `new_id'. Returns FALSE
+   if the ID could not be changed. */
+
+bool silc_client_replace_channel_id(SilcClient client,
+                                   SilcClientConnection conn,
+                                   SilcChannelEntry channel,
+                                   SilcChannelID *new_id)
+{
+  if (!new_id)
+    return FALSE;
+
+  SILC_LOG_DEBUG(("Old Channel ID id(%s)", 
+                 silc_id_render(channel->id, SILC_ID_CHANNEL)));
+  SILC_LOG_DEBUG(("New Channel ID id(%s)", 
+                 silc_id_render(new_id, SILC_ID_CHANNEL)));
+
+  silc_idcache_del_by_id(conn->channel_cache, channel->id);
+  silc_free(channel->id);
+  channel->id = new_id;
+  return silc_idcache_add(conn->channel_cache, channel->channel_name, 
+                         (void *)channel->id, (void *)channel, 0, NULL);
+
+}
+
 /* Finds entry for channel by the channel name. Returns the entry or NULL
    if the entry was not found. It is found only if the client is joined
    to the channel. */
@@ -816,39 +896,6 @@ void silc_client_get_channel_by_id_resolve(SilcClient client,
                              (void *)i);
 }
 
-/* Find channel entry by ID. This routine is used internally by the library. */
-
-SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client,
-                                              SilcClientConnection conn,
-                                              SilcChannelID *channel_id,
-                                              int query)
-{
-  SilcBuffer idp;
-  SilcChannelEntry channel;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  channel = silc_client_get_channel_by_id(client, conn, channel_id);
-  if (channel)
-    return channel;
-
-  if (query) {
-    /* Register our own command reply for this command */
-    silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
-                                silc_client_command_reply_identify_i, 0,
-                                ++conn->cmd_ident);
-
-    /* Send the command */
-    idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
-    silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, 
-                            conn->cmd_ident,
-                            1, 5, idp->data, idp->len);
-    silc_buffer_free(idp);
-  }
-
-  return NULL;
-}
-
 /* Finds entry for server by the server name. */
 
 SilcServerEntry silc_client_get_server(SilcClient client,
index 26b38e010e3311aa9b76ccc6b4da4b031d4d2bf2..b515baa4980fd22b03d6395f8fdf03a183f8720d 100644 (file)
@@ -1,16 +1,15 @@
 /*
 
-  idlist.h
+  idlist.h 
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 2001 - 2002 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
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
+  the Free Software Foundation; version 2 of the License.
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -21,6 +20,9 @@
 #ifndef IDLIST_H
 #define IDLIST_H
 
+typedef struct SilcChannelEntryStruct *SilcChannelEntry;
+
+/* Client entry status */
 typedef enum {
   SILC_CLIENT_STATUS_NONE       = 0x0000,
   SILC_CLIENT_STATUS_RESOLVING  = 0x0001,
@@ -51,13 +53,14 @@ typedef struct {
   bool generated;              /* TRUE if library generated the key */
   SilcClientKeyAgreement ke;   /* Current key agreement context or NULL */
   SilcClientStatus status;     /* Status mask */
+  SilcHashTable channels;      /* All channels client has joined */
 } *SilcClientEntry;
 
 /* Client and its mode on a channel */
 typedef struct SilcChannelUserStruct {
   SilcClientEntry client;
   uint32 mode;
-  struct SilcChannelUserStruct *next;
+  SilcChannelEntry channel;
 } *SilcChannelUser;
 
 /* Structure to hold one channel private key. */
@@ -70,14 +73,13 @@ typedef struct {
 
 /* Channel entry context. This is allocate for every channel client has
    joined to. This includes for example the channel specific keys */
-typedef struct SilcChannelEntryStruct {
+struct SilcChannelEntryStruct {
   char *channel_name;
   SilcChannelID *id;
   uint32 mode;
-  bool on_channel;
 
-  /* Joined clients */
-  SilcList clients;
+  /* All clients that has joined this channel */
+  SilcHashTable user_list;
 
   /* Channel keys */
   SilcCipher channel_key;                    /* The channel key */
@@ -94,7 +96,7 @@ typedef struct SilcChannelEntryStruct {
   SilcCipher old_channel_key;
   SilcHmac old_hmac;
   SilcTask rekey_task;
-} *SilcChannelEntry;
+};
 
 /* Server entry context. This represents one server. When server information
    is resolved with INFO command the server info is saved in this context. 
@@ -127,10 +129,15 @@ SilcClientEntry silc_idlist_get_client(SilcClient client,
                                       const char *nickname,
                                       const char *format,
                                       bool query);
-SilcChannelEntry silc_idlist_get_channel_by_id(SilcClient client,
-                                              SilcClientConnection conn,
-                                              SilcChannelID *channel_id,
-                                              int query);
+SilcChannelEntry silc_client_add_channel(SilcClient client,
+                                        SilcClientConnection conn,
+                                        const char *channel_name,
+                                        uint32 mode, 
+                                        SilcChannelID *channel_id);
+bool silc_client_replace_channel_id(SilcClient client,
+                                   SilcClientConnection conn,
+                                   SilcChannelEntry channel,
+                                   SilcChannelID *new_id);
 void silc_client_nickname_format(SilcClient client, 
                                 SilcClientConnection conn,
                                 SilcClientEntry client_entry);
index 5bcf556d9171cf49a8622784c6e1e4890d631b99..7bb917848aaecbcb56979466ed37ddc979c6bd79 100644 (file)
@@ -964,11 +964,11 @@ bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
  *
  * SYNOPSIS
  *
- *    typedef void (*SilcGetClientCallback)(SilcClient client,
- *                                          SilcClientConnection conn,
- *                                          SilcClientEntry *clients,
- *                                          uint32 clients_count,
- *                                          void *context);
+ *    typedef void (*SilcGetChannelCallback)(SilcClient client,
+ *                                           SilcClientConnection conn,
+ *                                           SilcChannelEntry *channels,
+ *                                           uint32 channels_count,
+ *                                           void *context);
  *
  * DESCRIPTION
  *
@@ -1117,6 +1117,23 @@ SilcServerEntry silc_client_get_server_by_id(SilcClient client,
 bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
                            SilcServerEntry server);
 
+/****f* silcclient/SilcClientAPI/silc_client_on_channel
+ *
+ * SYNOPSIS
+ *
+ *    SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
+ *                                           SilcClientEntry client_entry);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the ChannelUser entry if the `client_entry' is joined on the 
+ *    channel indicated by the `channel'. NULL if client is not joined on
+ *    the channel. 
+ *
+ ***/
+SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
+                                      SilcClientEntry client_entry);
+
 /* Command management (command.c) */
 
 /****f* silcclient/SilcClientAPI/silc_client_command_alloc
index 130d9fa72e4a3b80d90b1b372ad57d1bc7077e2e..31f333082cfbf0a4a109216a3fafc8c18fa90eac 100644 (file)
@@ -834,6 +834,18 @@ void silc_hash_table_list(SilcHashTable ht, SilcHashTableList *htl)
   htl->ht = ht;
   htl->entry = NULL;
   htl->index = 0;
+  htl->auto_rehash = ht->auto_rehash;
+
+  /* Disallow rehashing of the table while traversing the table */
+  ht->auto_rehash = FALSE;
+}
+
+/* Resets the `htl' SilcHashTableList. */
+
+void silc_hash_table_list_reset(SilcHashTableList *htl)
+{
+  /* Set back the original auto rehash value to the table */
+  htl->ht->auto_rehash = htl->auto_rehash;
 }
 
 /* Returns always the next entry in the hash table into the `key' and
index bdee0e10c69ffdf6c70c8e360612b611993f7b33..f05e99e0ef0aab4af8b2d4337e76e802cbe3de47 100644 (file)
@@ -80,6 +80,7 @@ typedef struct SilcHashTableStruct *SilcHashTable;
  *    silc_hash_table_list(hash_table, &htl);
  *    while (silc_hash_table_get(&htl, (void *)&key, (void *)&context))
  *      ...
+ *    silc_hash_table_list_reset(&htl);
  *
  * SOURCE
  */
@@ -90,6 +91,7 @@ struct SilcHashTableListStruct {
   SilcHashTable ht;
   void *entry;
   uint32 index;
+  bool auto_rehash;
 };
 /***/
 
@@ -383,11 +385,33 @@ void silc_hash_table_rehash(SilcHashTable ht, uint32 new_size);
  * DESCRIPTION
  *
  *    Prepares the `htl' SilcHashTableList sent as argument to be used in the
- *    hash table traversing with the silc_hash_table_get.
+ *    hash table traversing with the silc_hash_table_get.  After the hash
+ *    table traversing is completed the silc_hash_table_list_reset must be
+ *    called.
+ *
+ * NOTES
+ *
+ *    The hash table will not be rehashed during the traversing of the list,
+ *    even if the table was marked as auto rehashable.  The caller also must
+ *    not call silc_hash_table_rehash while traversing the list.
  *
  ***/
 void silc_hash_table_list(SilcHashTable ht, SilcHashTableList *htl);
 
+/****f* silcutil/SilcHashTableAPI/silc_hash_table_list_reset
+ *
+ * SYNOPSIS
+ *
+ *    void silc_hash_table_list_reset(SilcHashTableList *htl);
+ *
+ * DESCRIPTION
+ *
+ *    Resets the `htl' SilcHashTableList.  This must be called after the
+ *    hash table traversing is completed.
+ *
+ ***/
+void silc_hash_table_list_reset(SilcHashTableList *htl);
+
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_get
  *
  * SYNOPSIS
index 42d54f0dd92cc37dae3c243c247d15826fe11b1d..18581ffbb1d1fe07f17b9f3eda3b8c17e83363dd 100644 (file)
@@ -555,3 +555,4 @@ EXPORTS
        silc_log_get_file @ 846 ;
        silc_log_quick @ 847 ;
        silc_log_flushdelay @ 848 ;
+       silc_hash_table_list_reset @ 849 ;
index 7bec0254c94e4cefd72a897bd80c6cd759c53abf..655b2ce84517413c37642f7107bad8a197c65aa1 100644 (file)
@@ -162,3 +162,4 @@ EXPORTS
        silc_client_command_call @ 148 ;
        silc_client_command_reply_quit @ 149 ;
        silc_client_run_one @ 150 ;
+       silc_client_on_channel @ 151 ;