Cleaned up some SILC_LOG_DEBUG's in backup protocol code.
[silc.git] / apps / silcd / server_util.c
index 2a7cb7a74a36de7c7b6912b76c96000ce5df82e6..c5b6a696c3522b3428ed2f672e04ba05672cdb28 100644 (file)
@@ -28,22 +28,24 @@ extern char *server_version;
    keys are regnerated. This is called only by the function
    silc_server_remove_clients_by_server. */
 
-static void silc_server_remove_clients_channels(SilcServer server, 
-                                               SilcSocketConnection sock,
-                                               SilcClientEntry client,
-                                               SilcHashTable channels)
+static void
+silc_server_remove_clients_channels(SilcServer server,
+                                   SilcServerEntry server_entry,
+                                   SilcHashTable clients,
+                                   SilcClientEntry client,
+                                   SilcHashTable channels)
 {
   SilcChannelEntry channel;
-  SilcChannelClientEntry chl;
-  SilcHashTableList htl;
-  SilcBuffer clidp;
+  SilcChannelClientEntry chl, chl2;
+  SilcHashTableList htl, htl2;
 
   SILC_LOG_DEBUG(("Start"));
 
-  if (!client || !client->id)
+  if (!client)
     return;
 
-  clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+  if (silc_hash_table_find(clients, client, NULL, NULL))
+    silc_hash_table_del(clients, client);
 
   /* Remove the client from all channels. The client is removed from
      the channels' user list. */
@@ -73,7 +75,14 @@ static void silc_server_remove_clients_channels(SilcServer server,
       channel->global_users = FALSE;
 
     silc_free(chl);
-    server->stat.my_chanclients--;
+
+    /* Update statistics */
+    if (SILC_IS_LOCAL(client))
+      server->stat.my_chanclients--;
+    if (server->server_type == SILC_ROUTER) {
+      server->stat.cell_chanclients--;
+      server->stat.chanclients--;
+    }
 
     /* If there is not at least one local user on the channel then we don't
        need the channel entry anymore, we can remove it safely, unless the
@@ -87,13 +96,27 @@ static void silc_server_remove_clients_channels(SilcServer server,
       continue;
     }
 
+    /* Mark other local clients to the table of clients whom will receive
+       the SERVER_SIGNOFF notify. */
+    silc_hash_table_list(channel->user_list, &htl2);
+    while (silc_hash_table_get(&htl2, NULL, (void **)&chl2)) {
+      SilcClientEntry c = chl2->client;
+      if (!c)
+       continue;
+
+      /* Add client to table, if it's not from the signoff server */
+      if (c->router != server_entry &&
+         !silc_hash_table_find(clients, c, NULL, NULL))
+       silc_hash_table_add(clients, c, c);
+    }
+    silc_hash_table_list_reset(&htl2);
+
     /* Add the channel to the the channels list to regenerate the 
        channel key */
     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);
 }
 
 /* This function is used to remove all client entries by the server `entry'.
@@ -110,13 +133,11 @@ bool silc_server_remove_clients_by_server(SilcServer server,
   SilcIDCacheEntry id_cache = NULL;
   SilcClientEntry client = NULL;
   SilcBuffer idp;
-  SilcClientEntry *clients = NULL;
-  SilcUInt32 clients_c = 0;
   unsigned char **argv = NULL;
   SilcUInt32 *argv_lens = NULL, *argv_types = NULL, argc = 0;
   SilcHashTableList htl;
   SilcChannelEntry channel;
-  SilcHashTable channels;
+  SilcHashTable channels, clients;
   int i;
 
   SILC_LOG_DEBUG(("Start"));
@@ -126,6 +147,8 @@ bool silc_server_remove_clients_by_server(SilcServer server,
      from the channels. */
   channels = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
                                   NULL, NULL, TRUE);
+  clients = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
+                                 NULL, NULL, TRUE);
 
   if (server_signoff) {
     idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
@@ -153,13 +176,6 @@ bool silc_server_remove_clients_by_server(SilcServer server,
        }
 
        if (client->router != entry) {
-         if (server_signoff) {
-           clients = silc_realloc(clients, 
-                                  sizeof(*clients) * (clients_c + 1));
-           clients[clients_c] = client;
-           clients_c++;
-         }
-
          if (!silc_idcache_list_next(list, &id_cache))
            break;
          else
@@ -188,16 +204,16 @@ bool silc_server_remove_clients_by_server(SilcServer server,
        SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
        SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
 
+       silc_server_remove_clients_channels(server, entry, clients,
+                                           client, channels);
+       silc_server_del_from_watcher_list(server, client);
+
        /* 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);
-
-         /* Remove this client from watcher list if it is */
-         silc_server_del_from_watcher_list(server, client);
        }
 
        if (!silc_idcache_list_next(list, &id_cache))
@@ -220,13 +236,6 @@ bool silc_server_remove_clients_by_server(SilcServer server,
        }
        
        if (client->router != entry) {
-         if (server_signoff && client->connection) {
-           clients = silc_realloc(clients, 
-                                  sizeof(*clients) * (clients_c + 1));
-           clients[clients_c] = client;
-           clients_c++;
-         }
-
          if (!silc_idcache_list_next(list, &id_cache))
            break;
          else
@@ -255,8 +264,11 @@ bool silc_server_remove_clients_by_server(SilcServer server,
        SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
        SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
 
+       silc_server_remove_clients_channels(server, entry, clients,
+                                           client, channels);
+       silc_server_del_from_watcher_list(server, client);
+
        /* 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;
@@ -275,15 +287,15 @@ bool silc_server_remove_clients_by_server(SilcServer server,
   if (server_signoff) {
     SilcBuffer args, not;
 
+    SILC_LOG_DEBUG(("Sending SERVER_SIGNOFF for %d clients",
+                   argc - 1));
+
     /* Send SERVER_SIGNOFF notify to our primary router */
-    if (!server->standalone && server->router &&
-       server->router != entry) {
+    if (server->router != entry) {
       args = silc_argument_payload_encode(1, argv, argv_lens,
                                          argv_types);
-      silc_server_send_notify_args(server, 
-                                  server->router->connection,
-                                  server->server_type == SILC_SERVER ? 
-                                  FALSE : TRUE, 
+      silc_server_send_notify_args(server, SILC_PRIMARY_ROUTE(server),
+                                  SILC_BROADCAST(server),
                                   SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
                                   argc, args);
       silc_buffer_free(args);
@@ -295,11 +307,10 @@ bool silc_server_remove_clients_by_server(SilcServer server,
                                        argv_types);
     not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF, 
                                          argc, args);
-    silc_server_packet_send_clients(server, clients, clients_c,
+    silc_server_packet_send_clients(server, clients,
                                    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++)
@@ -307,6 +318,7 @@ bool silc_server_remove_clients_by_server(SilcServer server,
     silc_free(argv);
     silc_free(argv_lens);
     silc_free(argv_types);
+    silc_hash_table_free(clients);
   }
 
   /* We must now re-generate the channel key for all channels that had
@@ -450,7 +462,8 @@ silc_server_update_clients_by_real_server(SilcServer server,
    be the new source. This function also removes the clients that are
    *really* originated from `from' if `remove_from' is TRUE. These are
    clients that the `from' owns, and not just clients that are behind
-   the `from'. */
+   the `from'. If `from' is NULL then all non-local clients are switched
+   to `to'. */
 
 void silc_server_update_clients_by_server(SilcServer server, 
                                          SilcServerEntry from,
@@ -463,20 +476,23 @@ void silc_server_update_clients_by_server(SilcServer server,
   SilcClientEntry client = NULL;
   bool local;
 
-  SILC_LOG_DEBUG(("Start"));
-
-  SILC_LOG_DEBUG(("Updating %s", silc_id_render(from->id,
-                                               SILC_ID_SERVER)));
-  SILC_LOG_DEBUG(("to %s", silc_id_render(to->id,
-                                         SILC_ID_SERVER)));
-
+  if (from)
+    SILC_LOG_DEBUG(("Updating %s", silc_id_render(from->id,
+                                                 SILC_ID_SERVER)));
+  if (to)
+    SILC_LOG_DEBUG(("to %s", silc_id_render(to->id,
+                                           SILC_ID_SERVER)));
 
   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 entry is disabled skip it.  If entry is local to us, do not
+          switch it to anyone else, it is ours so skip it. */
+       if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
+           SILC_IS_LOCAL(client)) {
          if (!silc_idcache_list_next(list, &id_cache))
            break;
          else
@@ -489,26 +505,31 @@ void silc_server_update_clients_by_server(SilcServer server,
          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' */
-         if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
-                                            client->id->ip.data_len)) {
-           SILC_LOG_DEBUG(("Found really owned client, skip it"));
-           if (!silc_idcache_list_next(list, &id_cache))
-             break;
-           else
-             continue;
-         }
-
-         if (resolve_real_server) {
-           client->router = 
-             silc_server_update_clients_by_real_server(server, from, client,
-                                                       local, id_cache);
-           if (!client->router)
+       if (from) {
+         if (client->router == from) {
+           /* Skip clients that are *really* owned by the `from' */
+           if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
+                                              client->id->ip.data_len)) {
+             SILC_LOG_DEBUG(("Found really owned client, skip it"));
+             if (!silc_idcache_list_next(list, &id_cache))
+               break;
+             else
+               continue;
+           }
+
+           if (resolve_real_server) {
+             client->router = 
+               silc_server_update_clients_by_real_server(server, from, client,
+                                                         local, id_cache);
+             if (!client->router)
+               client->router = to;
+           } else {
              client->router = to;
-         } else {
-           client->router = to;
+           }
          }
+       } else {
+         /* All are changed */
+         client->router = to;
        }
 
        if (!silc_idcache_list_next(list, &id_cache))
@@ -523,7 +544,11 @@ void silc_server_update_clients_by_server(SilcServer server,
     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 entry is disabled skip it.  If entry is local to us, do not
+          switch it to anyone else, it is ours so skip it. */
+       if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
+           SILC_IS_LOCAL(client)) {
          if (!silc_idcache_list_next(list, &id_cache))
            break;
          else
@@ -536,26 +561,31 @@ void silc_server_update_clients_by_server(SilcServer server,
          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' */
-         if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
-                                            client->id->ip.data_len)) {
-           SILC_LOG_DEBUG(("Found really owned client, skip it"));
-           if (!silc_idcache_list_next(list, &id_cache))
-             break;
-           else
-             continue;
-         }
-
-         if (resolve_real_server) {
-           client->router = 
-             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 */
-         } else {
-           client->router = to;
+       if (from) {
+         if (client->router == from) {
+           /* Skip clients that are *really* owned by the `from' */
+           if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
+                                              client->id->ip.data_len)) {
+             SILC_LOG_DEBUG(("Found really owned client, skip it"));
+             if (!silc_idcache_list_next(list, &id_cache))
+               break;
+             else
+               continue;
+           }
+
+           if (resolve_real_server) {
+             client->router = 
+               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 */
+           } else {
+             client->router = to;
+           }
          }
+       } else {
+         /* All are changed */
+         client->router = to;
        }
 
        if (!silc_idcache_list_next(list, &id_cache))
@@ -573,26 +603,48 @@ void silc_server_update_clients_by_server(SilcServer server,
 }
 
 /* Updates servers that are from `from' to be originated from `to'.  This
-   will also update the server's connection to `to's connection. */
+   will also update the server's connection to `to's connection. If
+   `local_toggle_enabled' is TRUE then local server's connections are
+   enabled, if FALSE they are disabled. */
 
 void silc_server_update_servers_by_server(SilcServer server, 
                                          SilcServerEntry from,
-                                         SilcServerEntry to)
+                                         SilcServerEntry to,
+                                         bool local_toggle_enabled)
 {
   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 (SILC_IS_LOCAL(server_entry)) {
+         if (server_entry != server->id_entry) {
+           if (local_toggle_enabled)
+             server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+           else
+             server_entry->data.status |= SILC_IDLIST_STATUS_DISABLED;
+         }
+
+         /* If entry is local to us, do not switch it to any oneelse,
+            it is ours. */
+         if (!silc_idcache_list_next(list, &id_cache))
+           break;
+         else
+           continue;
+       }
+
        if (server_entry->router == from) {
+         SILC_LOG_DEBUG(("Updating server (local) %s",
+                         server_entry->server_name ? 
+                         server_entry->server_name : ""));
          server_entry->router = to;
          server_entry->connection = to->connection;
        }
+
        if (!silc_idcache_list_next(list, &id_cache))
          break;
       }
@@ -604,10 +656,31 @@ void silc_server_update_servers_by_server(SilcServer server,
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
        server_entry = (SilcServerEntry)id_cache->context;
+
+       if (SILC_IS_LOCAL(server_entry)) {
+         if (server_entry != server->id_entry) {
+           if (local_toggle_enabled)
+             server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+           else
+             server_entry->data.status |= SILC_IDLIST_STATUS_DISABLED;
+         }
+
+         /* If entry is local to us, do not switch it to anyone else,
+            it is ours. */
+         if (!silc_idcache_list_next(list, &id_cache))
+           break;
+         else
+           continue;
+       }
+
        if (server_entry->router == from) {
+         SILC_LOG_DEBUG(("Updating server (global) %s",
+                         server_entry->server_name ? 
+                         server_entry->server_name : ""));
          server_entry->router = to;
          server_entry->connection = to->connection;
        }
+
        if (!silc_idcache_list_next(list, &id_cache))
          break;
       }
@@ -625,7 +698,7 @@ void silc_server_remove_channels_by_server(SilcServer server,
   SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry channel = NULL;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Removing channels by server"));
 
   if (silc_idcache_get_all(server->global_list->channels, &list)) {
     if (silc_idcache_list_first(list, &id_cache)) {
@@ -651,7 +724,7 @@ void silc_server_update_channels_by_server(SilcServer server,
   SilcIDCacheEntry id_cache = NULL;
   SilcChannelEntry channel = NULL;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Updating channels by server"));
 
   if (silc_idcache_get_all(server->global_list->channels, &list)) {
     if (silc_idcache_list_first(list, &id_cache)) {
@@ -722,13 +795,25 @@ bool silc_server_channel_delete(SilcServer server,
   if (delchan) {
     SILC_LOG_DEBUG(("Deleting %s channel", channel->channel_name));
 
+    /* Update statistics */
+    if (server->server_type == SILC_ROUTER)
+      server->stat.chanclients -= channel->user_count;
+
     /* Totally delete the channel and all users on the channel. The
        users are deleted automatically in silc_idlist_del_channel. */
     silc_schedule_task_del_by_context(server->schedule, channel->rekey);
-    if (silc_idlist_del_channel(server->local_list, channel))
+    if (silc_idlist_del_channel(server->local_list, channel)) {
       server->stat.my_channels--;
-    else
-      silc_idlist_del_channel(server->global_list, channel);
+      if (server->server_type == SILC_ROUTER) {
+       server->stat.channels--;
+       server->stat.cell_channels--;
+      }
+    } else {
+      if (silc_idlist_del_channel(server->global_list, channel))
+       if (server->server_type == SILC_ROUTER)
+         server->stat.channels--;
+    }
+
     return FALSE;
   }
 
@@ -739,6 +824,15 @@ bool silc_server_channel_delete(SilcServer server,
     silc_hash_table_del(chl->client->channels, channel);
     silc_hash_table_del(channel->user_list, chl->client);
     channel->user_count--;
+
+    /* Update statistics */
+    if (SILC_IS_LOCAL(chl->client))
+      server->stat.my_chanclients--;
+    if (server->server_type == SILC_ROUTER) {
+      server->stat.cell_chanclients--;
+      server->stat.chanclients--;
+    }
+
     silc_free(chl);
   }
   silc_hash_table_list_reset(&htl);
@@ -918,6 +1012,8 @@ bool silc_server_connection_allowed(SilcServer server,
   SilcUInt32 r_software_version, l_software_version;
   char *r_vendor_version = NULL, *l_vendor_version;
 
+  SILC_LOG_DEBUG(("Checking whether connection is allowed"));
+
   /* Check version */
 
   l_protocol_version = 
@@ -1019,14 +1115,17 @@ bool silc_server_check_cmode_rights(SilcServer server,
   if (is_op && is_fo)
     return TRUE;
 
+  /* Founder implies operator */
+  if (is_fo)
+    is_op = TRUE;
+
   /* We know that client is channel operator, check that they are not
      changing anything that requires channel founder rights. Rest of the
      modes are available automatically for channel operator. */
 
   if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
-    if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
-      if (is_op && !is_fo)
-       return FALSE;
+    if (is_op && !is_fo)
+      return FALSE;
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
       if (is_op && !is_fo)
@@ -1035,9 +1134,10 @@ bool silc_server_check_cmode_rights(SilcServer server,
   }
   
   if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
-    if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE))
+    if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
       if (is_op && !is_fo)
        return FALSE;
+    }
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
       if (is_op && !is_fo)
@@ -1046,9 +1146,10 @@ bool silc_server_check_cmode_rights(SilcServer server,
   }
 
   if (mode & SILC_CHANNEL_MODE_CIPHER) {
-    if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER))
+    if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
       if (is_op && !is_fo)
        return FALSE;
+    }
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
       if (is_op && !is_fo)
@@ -1057,9 +1158,10 @@ bool silc_server_check_cmode_rights(SilcServer server,
   }
   
   if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
-    if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH))
+    if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
       if (is_op && !is_fo)
        return FALSE;
+    }
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
       if (is_op && !is_fo)
@@ -1068,9 +1170,10 @@ bool silc_server_check_cmode_rights(SilcServer server,
   }
   
   if (mode & SILC_CHANNEL_MODE_SILENCE_USERS) {
-    if (!(channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS))
+    if (!(channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS)) {
       if (is_op && !is_fo)
        return FALSE;
+    }
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS) {
       if (is_op && !is_fo)
@@ -1079,9 +1182,10 @@ bool silc_server_check_cmode_rights(SilcServer server,
   }
   
   if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS) {
-    if (!(channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS))
+    if (!(channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS)) {
       if (is_op && !is_fo)
        return FALSE;
+    }
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS) {
       if (is_op && !is_fo)
@@ -1138,6 +1242,8 @@ void silc_server_send_connect_notifys(SilcServer server,
 {
   SilcIDListData idata = (SilcIDListData)client;
 
+  SILC_LOG_DEBUG(("Send welcome notifys"));
+
   /* Send some nice info to the client */
   SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                          ("Welcome to the SILC Network %s",
@@ -1146,11 +1252,23 @@ void silc_server_send_connect_notifys(SilcServer server,
                          ("Your host is %s, running version %s",
                           server->server_name, server_version));
 
-  if (server->stat.clients && server->stat.servers + 1)
+  if (server->server_type == SILC_ROUTER) {
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                           ("There are %d clients on %d servers in SILC "
-                            "Network", server->stat.clients,
-                            server->stat.servers + 1));
+                           ("There are %d clients, %d servers and %d "
+                            "routers in SILC Network",
+                            server->stat.clients, server->stat.servers + 1,
+                            server->stat.routers));
+  } else {
+    if (server->stat.clients && server->stat.servers + 1)
+      SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+                             ("There are %d clients, %d servers and %d "
+                              "routers in SILC Network",
+                              server->stat.clients, server->stat.servers + 1,
+                              (server->standalone ? 0 :
+                               !server->stat.routers ? 1 :
+                               server->stat.routers)));
+  }
+
   if (server->stat.cell_clients && server->stat.cell_servers + 1)
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                            ("There are %d clients on %d server in our cell",
@@ -1208,6 +1326,9 @@ void silc_server_kill_client(SilcServer server,
 {
   SilcBuffer killed, killer;
 
+  SILC_LOG_DEBUG(("Killing client %s", 
+                 silc_id_render(remote_client->id, SILC_ID_CLIENT)));
+
   /* Send the KILL notify packets. First send it to the channel, then
      to our primary router and then directly to the client who is being
      killed right now. */
@@ -1225,10 +1346,9 @@ void silc_server_kill_client(SilcServer server,
                                      killer->data, killer->len);
 
   /* Send KILLED notify to primary route */
-  if (!server->standalone)
-    silc_server_send_notify_killed(server, server->router->connection, TRUE,
-                                  remote_client->id, comment, 
-                                  killer_id, killer_id_type);
+  silc_server_send_notify_killed(server, SILC_PRIMARY_ROUTE(server),
+                                SILC_BROADCAST(server), remote_client->id,
+                                comment, killer_id, killer_id_type);
 
   /* Send KILLED notify to the client directly */
   if (remote_client->connection || remote_client->router)
@@ -1253,17 +1373,21 @@ void silc_server_kill_client(SilcServer server,
   } else {
     /* Update statistics */
     server->stat.clients--;
-    server->stat.my_clients--;
     if (server->stat.cell_clients)
       server->stat.cell_clients--;
     SILC_OPER_STATS_UPDATE(remote_client, server, SILC_UMODE_SERVER_OPERATOR);
     SILC_OPER_STATS_UPDATE(remote_client, router, SILC_UMODE_ROUTER_OPERATOR);
 
+    if (SILC_IS_LOCAL(remote_client)) {
+      server->stat.my_clients--;
+      silc_schedule_task_del_by_context(server->schedule, remote_client);
+      silc_idlist_del_data(remote_client);
+    }
+
     /* Remove remote client */
     if (!silc_idlist_del_client(server->global_list, remote_client)) {
       /* Remove this client from watcher list if it is */
       silc_server_del_from_watcher_list(server, remote_client);
-
       silc_idlist_del_client(server->local_list, remote_client);  
     }
   }
@@ -1317,7 +1441,8 @@ bool silc_server_check_watcher_list(SilcServer server,
   unsigned char hash[16];
   WatcherNotifyContext n;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Checking watcher list %s",
+                 client->nickname ? client->nickname : (unsigned char *)""));
 
   /* If the watching is rejected by the client do nothing */
   if (client->mode & SILC_UMODE_REJECT_WATCHING)
@@ -1362,8 +1487,9 @@ bool silc_server_del_from_watcher_list(SilcServer server,
     if (entry == client) {
       silc_hash_table_del_by_context(server->watcher_list, key, client);
 
-      SILC_LOG_DEBUG(("Removing %s from WATCH list",
-                     silc_id_render(client->id, SILC_ID_CLIENT)));
+      if (client->id)
+       SILC_LOG_DEBUG(("Removing %s from WATCH list",
+                       silc_id_render(client->id, SILC_ID_CLIENT)));
 
       /* Now check whether there still exists entries with this key, if not
         then free the key to not leak memory. */
@@ -1390,9 +1516,12 @@ bool silc_server_force_cumode_change(SilcServer server,
   SilcBuffer idp1, idp2;
   unsigned char cumode[4];
 
-  silc_server_send_notify_cumode(server, sock, FALSE, channel, forced_mode,
-                                server->id, SILC_ID_SERVER,
-                                chl->client->id);
+  SILC_LOG_DEBUG(("Enforcing sender to change mode"));
+
+  if (sock)
+    silc_server_send_notify_cumode(server, sock, FALSE, channel, forced_mode,
+                                  server->id, SILC_ID_SERVER,
+                                  chl->client->id, NULL);
 
   idp1 = silc_id_payload_encode(server->id, SILC_ID_SERVER);
   idp2 = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
@@ -1404,4 +1533,28 @@ bool silc_server_force_cumode_change(SilcServer server,
                                     idp2->data, idp2->len);
   silc_buffer_free(idp1);
   silc_buffer_free(idp2);
+
+  return TRUE;
+}
+
+/* Find active socket connection by the IP address and port indicated by
+   `ip' and `port', and socket connection type of `type'. */
+
+SilcSocketConnection
+silc_server_find_socket_by_host(SilcServer server,
+                               SilcSocketType type,
+                               const char *ip, SilcUInt16 port)
+{
+  int i;
+
+  for (i = 0; i < server->config->param.connections_max; i++) {
+    if (!server->sockets[i])
+      continue;
+    if (!strcmp(server->sockets[i]->ip, ip) &&
+       (!port || server->sockets[i]->port == port) &&
+       server->sockets[i]->type == type)
+      return server->sockets[i];
+  }
+
+  return NULL;
 }