updates.
[silc.git] / apps / silcd / server_util.c
index 30c9e157eebaebd1015ec5847fb24b8d2b825213..1f21972ee1af751f96665a0a4e0fe000f1771a9c 100644 (file)
@@ -62,9 +62,10 @@ static void silc_server_remove_clients_channels(SilcServer server,
       if (channel->rekey)
        silc_schedule_task_del_by_context(server->schedule, channel->rekey);
 
-      if (!silc_idlist_del_channel(server->local_list, channel))
-       silc_idlist_del_channel(server->global_list, channel);
-      server->stat.my_channels--;
+      if (silc_idlist_del_channel(server->local_list, channel))
+       server->stat.my_channels--;
+      else 
+        silc_idlist_del_channel(server->global_list, channel);
       continue;
     }
 
@@ -96,7 +97,7 @@ static void silc_server_remove_clients_channels(SilcServer server,
        SilcChannelClientEntry chl2;
        SilcHashTableList htl2;
 
-       channel->id = NULL;
+       channel->disabled = TRUE;
 
        silc_hash_table_list(channel->user_list, &htl2);
        while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
@@ -108,9 +109,10 @@ static void silc_server_remove_clients_channels(SilcServer server,
       }
 
       /* Remove the channel entry */
-      if (!silc_idlist_del_channel(server->local_list, channel))
-       silc_idlist_del_channel(server->global_list, channel);
-      server->stat.my_channels--;
+      if (silc_idlist_del_channel(server->local_list, channel))
+       server->stat.my_channels--;
+      else 
+        silc_idlist_del_channel(server->global_list, channel);
       continue;
     }
 
@@ -180,7 +182,7 @@ bool silc_server_remove_clients_by_server(SilcServer server,
        }
 
        if (client->router != entry) {
-         if (server_signoff && client->connection) {
+         if (server_signoff) {
            clients = silc_realloc(clients, 
                                   sizeof(*clients) * (clients_c + 1));
            clients[clients_c] = client;
@@ -210,7 +212,11 @@ bool silc_server_remove_clients_by_server(SilcServer server,
 
        /* Remove the client entry */
        silc_server_remove_clients_channels(server, NULL, client, channels);
-       silc_idlist_del_client(server->local_list, client);
+       client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+       id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+       server->stat.clients--;
+       if (server->server_type == SILC_ROUTER)
+         server->stat.cell_clients--;
 
        if (!silc_idcache_list_next(list, &id_cache))
          break;
@@ -262,7 +268,11 @@ bool silc_server_remove_clients_by_server(SilcServer server,
 
        /* Remove the client entry */
        silc_server_remove_clients_channels(server, NULL, client, channels);
-       silc_idlist_del_client(server->global_list, client);
+       client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+       id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+       server->stat.clients--;
+       if (server->server_type == SILC_ROUTER)
+         server->stat.cell_clients--;
 
        if (!silc_idcache_list_next(list, &id_cache))
          break;
@@ -273,7 +283,7 @@ bool silc_server_remove_clients_by_server(SilcServer server,
 
   /* Send the SERVER_SIGNOFF notify */
   if (server_signoff) {
-    SilcBuffer args;
+    SilcBuffer args, not;
 
     /* Send SERVER_SIGNOFF notify to our primary router */
     if (!server->standalone && server->router &&
@@ -289,17 +299,19 @@ bool silc_server_remove_clients_by_server(SilcServer server,
       silc_buffer_free(args);
     }
 
+    /* Send to local clients. We also send the list of client ID's that
+       is to be removed for those servers that would like to use that list. */
     args = silc_argument_payload_encode(argc, argv, argv_lens,
                                        argv_types);
-    /* Send to local clients */
-    for (i = 0; i < clients_c; i++) {
-      silc_server_send_notify_args(server, clients[i]->connection,
-                                  FALSE, SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
-                                  argc, args);
-    }
+    not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF, 
+                                         argc, args);
+    silc_server_packet_send_clients(server, clients, clients_c,
+                                   SILC_PACKET_NOTIFY, 0, FALSE,
+                                   not->data, not->len, FALSE);
 
     silc_free(clients);
     silc_buffer_free(args);
+    silc_buffer_free(not);
     for (i = 0; i < argc; i++)
       silc_free(argv[i]);
     silc_free(argv);
@@ -351,14 +363,28 @@ silc_server_update_clients_by_real_server(SilcServer server,
        SILC_LOG_DEBUG(("Found (local) %s",
                        silc_id_render(server_entry->id, SILC_ID_SERVER)));
 
-       /* If the client is not marked as local then move it to local list
-          since the server is local. */
-       if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
-         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);
-         silc_idcache_del_by_context(server->global_list->clients, client);
+       if (!server_entry->data.send_key && server_entry->router) {
+         SILC_LOG_DEBUG(("Server not locally connected, use its router"));
+         /* If the client is not marked as local then move it to local list
+            since the server is local. */
+         if (!local) {
+           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, NULL);
+           silc_idcache_del_by_context(server->global_list->clients, client);
+         }
+         server_entry = server_entry->router;
+       } else {
+         /* If the client is not marked as local then move it to local list
+            since the server is local. */
+         if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
+           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, NULL);
+           silc_idcache_del_by_context(server->global_list->clients, client);
+         }
        }
 
        silc_idcache_list_free(list);
@@ -384,14 +410,28 @@ silc_server_update_clients_by_real_server(SilcServer server,
        SILC_LOG_DEBUG(("Found (global) %s",
                        silc_id_render(server_entry->id, SILC_ID_SERVER)));
 
-       /* If the client is marked as local then move it to global list
-          since the server is global. */
-       if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
-         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);
-         silc_idcache_del_by_context(server->local_list->clients, client);
+       if (!server_entry->data.send_key && server_entry->router) {
+         SILC_LOG_DEBUG(("Server not locally connected, use its router"));
+         /* If the client is marked as local then move it to global list
+            since the server is global. */
+         if (local) {
+           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, NULL);
+           silc_idcache_del_by_context(server->local_list->clients, client);
+         }
+         server_entry = server_entry->router;
+       } else {
+         /* If the client is marked as local then move it to global list
+            since the server is global. */
+         if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
+           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, NULL);
+           silc_idcache_del_by_context(server->local_list->clients, client);
+         }
        }
 
        silc_idcache_list_free(list);
@@ -437,12 +477,11 @@ void silc_server_update_clients_by_server(SilcServer server,
                                          SILC_ID_SERVER)));
 
 
-  local = TRUE;
-  if (silc_idcache_get_all(server->local_list->clients, &list)) {
+  local = FALSE;
+  if (silc_idcache_get_all(server->global_list->clients, &list)) {
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
        client = (SilcClientEntry)id_cache->context;
-
        if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
          if (!silc_idcache_list_next(list, &id_cache))
            break;
@@ -450,8 +489,11 @@ void silc_server_update_clients_by_server(SilcServer server,
            continue;
        }
 
-       SILC_LOG_DEBUG(("Client (local) %s", 
+       SILC_LOG_DEBUG(("Client (global) %s", 
                        silc_id_render(client->id, SILC_ID_CLIENT)));
+       if (client->router)
+         SILC_LOG_DEBUG(("Client->router (global) %s", 
+                         silc_id_render(client->router->id, SILC_ID_SERVER)));
 
        if (client->router == from) {
          /* Skip clients that are *really* owned by the `from' */
@@ -469,7 +511,7 @@ void silc_server_update_clients_by_server(SilcServer server,
              silc_server_update_clients_by_real_server(server, from, client,
                                                        local, id_cache);
            if (!client->router)
-             client->router = from; /* on local list put old from */
+             client->router = to;
          } else {
            client->router = to;
          }
@@ -482,13 +524,11 @@ void silc_server_update_clients_by_server(SilcServer server,
     silc_idcache_list_free(list);
   }
 
-  local = FALSE;
-  if (silc_idcache_get_all(server->global_list->clients, &list)) {
+  local = TRUE;
+  if (silc_idcache_get_all(server->local_list->clients, &list)) {
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
        client = (SilcClientEntry)id_cache->context;
-       
-
        if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
          if (!silc_idcache_list_next(list, &id_cache))
            break;
@@ -496,8 +536,11 @@ void silc_server_update_clients_by_server(SilcServer server,
            continue;
        }
 
-       SILC_LOG_DEBUG(("Client (global) %s", 
+       SILC_LOG_DEBUG(("Client (local) %s", 
                        silc_id_render(client->id, SILC_ID_CLIENT)));
+       if (client->router)
+         SILC_LOG_DEBUG(("Client->router (local) %s", 
+                         silc_id_render(client->router->id, SILC_ID_SERVER)));
 
        if (client->router == from) {
          /* Skip clients that are *really* owned by the `from' */
@@ -515,7 +558,7 @@ void silc_server_update_clients_by_server(SilcServer server,
              silc_server_update_clients_by_real_server(server, from, client,
                                                        local, id_cache);
            if (!client->router)
-             client->router = to;
+             client->router = from; /* on local list put old from */
          } else {
            client->router = to;
          }
@@ -535,6 +578,101 @@ void silc_server_update_clients_by_server(SilcServer server,
     silc_server_remove_clients_by_server(server, from, TRUE);
 }
 
+/* Updates servers that are from `from' to be originated from `to'.  This
+   will also update the server's connection to `to's connection. */
+
+void silc_server_update_servers_by_server(SilcServer server, 
+                                         SilcServerEntry from,
+                                         SilcServerEntry to)
+{
+  SilcIDCacheList list = NULL;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcServerEntry server_entry = NULL;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (silc_idcache_get_all(server->local_list->servers, &list)) {
+    if (silc_idcache_list_first(list, &id_cache)) {
+      while (id_cache) {
+       server_entry = (SilcServerEntry)id_cache->context;
+       if (server_entry->router == from) {
+         server_entry->router = to;
+         server_entry->connection = to->connection;
+       }
+       if (!silc_idcache_list_next(list, &id_cache))
+         break;
+      }
+    }
+    silc_idcache_list_free(list);
+  }
+
+  if (silc_idcache_get_all(server->global_list->servers, &list)) {
+    if (silc_idcache_list_first(list, &id_cache)) {
+      while (id_cache) {
+       server_entry = (SilcServerEntry)id_cache->context;
+       if (server_entry->router == from) {
+         server_entry->router = to;
+         server_entry->connection = to->connection;
+       }
+       if (!silc_idcache_list_next(list, &id_cache))
+         break;
+      }
+    }
+    silc_idcache_list_free(list);
+  }
+}
+
+/* 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. */