updates.
[silc.git] / apps / silcd / server_util.c
index d0488095ef5bc64af9752cb4895796b5dedfe707..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);
 }
@@ -210,13 +212,21 @@ bool silc_server_remove_clients_by_server(SilcServer server,
          silc_buffer_free(idp);
        }
 
-       /* Remove the client entry */
-       silc_server_remove_clients_channels(server, NULL, client, channels);
-       client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
-       id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+       /* Update statistics */
        server->stat.clients--;
        if (server->server_type == SILC_ROUTER)
          server->stat.cell_clients--;
+       SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+       SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
+       /* Remove the client entry */
+       silc_server_remove_clients_channels(server, NULL, client, channels);
+       if (!server_signoff) {
+         client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+         id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+       } else {
+         silc_idlist_del_client(server->local_list, client);
+       }
 
        if (!silc_idcache_list_next(list, &id_cache))
          break;
@@ -266,13 +276,21 @@ bool silc_server_remove_clients_by_server(SilcServer server,
          silc_buffer_free(idp);
        }
 
-       /* Remove the client entry */
-       silc_server_remove_clients_channels(server, NULL, client, channels);
-       client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
-       id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+       /* Update statistics */
        server->stat.clients--;
        if (server->server_type == SILC_ROUTER)
          server->stat.cell_clients--;
+       SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+       SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
+       /* Remove the client entry */
+       silc_server_remove_clients_channels(server, NULL, client, channels);
+       if (!server_signoff) {
+         client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+         id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+       } else {
+         silc_idlist_del_client(server->global_list, client);
+       }
 
        if (!silc_idcache_list_next(list, &id_cache))
          break;
@@ -324,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)
@@ -335,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;
@@ -371,7 +393,7 @@ silc_server_update_clients_by_real_server(SilcServer server,
            SILC_LOG_DEBUG(("Moving client to local list"));
            silc_idcache_add(server->local_list->clients, client_cache->name,
                             client_cache->id, client_cache->context,
-                            client_cache->expire);
+                            client_cache->expire, NULL);
            silc_idcache_del_by_context(server->global_list->clients, client);
          }
          server_entry = server_entry->router;
@@ -382,7 +404,7 @@ silc_server_update_clients_by_real_server(SilcServer server,
            SILC_LOG_DEBUG(("Moving client to local list"));
            silc_idcache_add(server->local_list->clients, client_cache->name,
                             client_cache->id, client_cache->context,
-                            client_cache->expire);
+                            client_cache->expire, NULL);
            silc_idcache_del_by_context(server->global_list->clients, client);
          }
        }
@@ -418,7 +440,7 @@ silc_server_update_clients_by_real_server(SilcServer server,
            SILC_LOG_DEBUG(("Moving client to global list"));
            silc_idcache_add(server->global_list->clients, client_cache->name,
                             client_cache->id, client_cache->context,
-                            client_cache->expire);
+                            client_cache->expire, NULL);
            silc_idcache_del_by_context(server->local_list->clients, client);
          }
          server_entry = server_entry->router;
@@ -429,7 +451,7 @@ silc_server_update_clients_by_real_server(SilcServer server,
            SILC_LOG_DEBUG(("Moving client to global list"));
            silc_idcache_add(server->global_list->clients, client_cache->name,
                             client_cache->id, client_cache->context,
-                            client_cache->expire);
+                            client_cache->expire, NULL);
            silc_idcache_del_by_context(server->local_list->clients, client);
          }
        }
@@ -622,6 +644,57 @@ void silc_server_update_servers_by_server(SilcServer server,
   }
 }
 
+/* Removes channels that are from `from. */
+
+void silc_server_remove_channels_by_server(SilcServer server, 
+                                          SilcServerEntry from)
+{
+  SilcIDCacheList list = NULL;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry channel = NULL;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (silc_idcache_get_all(server->global_list->channels, &list)) {
+    if (silc_idcache_list_first(list, &id_cache)) {
+      while (id_cache) {
+       channel = (SilcChannelEntry)id_cache->context;
+       if (channel->router == from)
+         silc_idlist_del_channel(server->global_list, channel);
+       if (!silc_idcache_list_next(list, &id_cache))
+         break;
+      }
+    }
+    silc_idcache_list_free(list);
+  }
+}
+
+/* Updates channels that are from `from' to be originated from `to'.  */
+
+void silc_server_update_channels_by_server(SilcServer server, 
+                                          SilcServerEntry from,
+                                          SilcServerEntry to)
+{
+  SilcIDCacheList list = NULL;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry channel = NULL;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (silc_idcache_get_all(server->global_list->channels, &list)) {
+    if (silc_idcache_list_first(list, &id_cache)) {
+      while (id_cache) {
+       channel = (SilcChannelEntry)id_cache->context;
+       if (channel->router == from)
+         channel->router = to;
+       if (!silc_idcache_list_next(list, &id_cache))
+         break;
+      }
+    }
+    silc_idcache_list_free(list);
+  }
+}
+
 /* Checks whether given channel has global users.  If it does this returns
    TRUE and FALSE if there is only locally connected clients on the channel. */
 
@@ -632,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;
 }
@@ -649,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;
 }
@@ -667,8 +746,44 @@ bool silc_server_client_on_channel(SilcClientEntry client,
   if (!client || !channel)
     return FALSE;
 
-  if (silc_hash_table_find(client->channels, channel, NULL, NULL))
-    return TRUE;
+  return silc_hash_table_find(client->channels, channel, NULL, NULL);
+}
+
+/* Checks string for bad characters and returns TRUE if they are found. */
+
+bool silc_server_name_bad_chars(const char *name, uint32 name_len)
+{
+  int i;
+
+  for (i = 0; i < name_len; i++) {
+    if (!isascii(name[i]))
+      return TRUE;
+    if (name[i] <= 32) return TRUE;
+    if (name[i] == ' ') return TRUE;
+    if (name[i] == '*') return TRUE;
+    if (name[i] == '?') return TRUE;
+    if (name[i] == ',') return TRUE;
+  }
 
   return FALSE;
 }
+
+/* Modifies the `name' if it includes bad characters and returns new
+   allocated name that does not include bad characters. */
+
+char *silc_server_name_modify_bad(const char *name, uint32 name_len)
+{
+  int i;
+  char *newname = strdup(name);
+
+  for (i = 0; i < name_len; i++) {
+    if (!isascii(newname[i])) newname[i] = '_';
+    if (newname[i] <= 32) newname[i] = '_';
+    if (newname[i] == ' ') newname[i] = '_';
+    if (newname[i] == '*') newname[i] = '_';
+    if (newname[i] == '?') newname[i] = '_';
+    if (newname[i] == ',') newname[i] = '_';
+  }
+
+  return newname;
+}