Added silc_server_send_opers[_notify] to send packets to operators.
[silc.git] / apps / silcd / packet_receive.c
index 9a0a7ba802671f962dc7216466d5dc2f1b7e9b57..4abfcfb86ba5a70f822fd47e9c96b9b3fd5e65cc 100644 (file)
@@ -50,14 +50,11 @@ void silc_server_notify(SilcServer server,
   SilcUInt32 tmp_len;
   bool local;
 
-  SILC_LOG_DEBUG(("Start"));
-
   if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
-      packet->src_id_type != SILC_ID_SERVER)
-    return;
-
-  if (!packet->dst_id)
+      packet->src_id_type != SILC_ID_SERVER || !packet->dst_id) {
+    SILC_LOG_DEBUG(("Bad notify packet received"));
     return;
+  }
 
   /* If the packet is destined directly to a client then relay the packet
      before processing it. */
@@ -86,7 +83,7 @@ void silc_server_notify(SilcServer server,
      we will broadcast it. The sending socket really cannot be router or
      the router is buggy. If this packet is coming from router then it must
      have the broadcast flag set already and we won't do anything. */
-  if (!server->standalone && server->server_type == SILC_ROUTER &&
+  if (server->server_type == SILC_ROUTER &&
       sock->type == SILC_SOCKET_TYPE_SERVER &&
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received Notify packet"));
@@ -97,12 +94,12 @@ void silc_server_notify(SilcServer server,
       if (!channel_id)
        goto out;
 
-      silc_server_packet_send_dest(server, server->router->connection
-                                  packet->type,
-                                  packet->flags | SILC_PACKET_FLAG_BROADCAST, 
+      silc_server_packet_send_dest(server, SILC_PRIMARY_ROUTE(server)
+                                  packet->type, packet->flags | 
+                                  SILC_PACKET_FLAG_BROADCAST, 
                                   channel_id, SILC_ID_CHANNEL,
-                                  packet->buffer->data, packet->buffer->len, 
-                                  FALSE);
+                                  packet->buffer->data, 
+                                  packet->buffer->len, FALSE);
       silc_server_backup_send_dest(server, (SilcServerEntry)sock->user_data, 
                                   packet->type, packet->flags,
                                   channel_id, SILC_ID_CHANNEL,
@@ -110,7 +107,7 @@ void silc_server_notify(SilcServer server,
                                   FALSE, TRUE);
     } else {
       /* Packet is destined to client or server */
-      silc_server_packet_send(server, server->router->connection
+      silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server)
                              packet->type,
                              packet->flags | SILC_PACKET_FLAG_BROADCAST, 
                              packet->buffer->data, packet->buffer->len, 
@@ -149,6 +146,7 @@ void silc_server_notify(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->local_list, 
                                               channel_id, NULL);
       if (!channel) {
+       SILC_LOG_DEBUG(("Notify for unknown channel"));
        silc_free(channel_id);
        goto out;
       }
@@ -220,10 +218,17 @@ void silc_server_notify(SilcServer server,
     chl->client = client;
     chl->channel = channel;
 
-    /* If this is the first one on the channel then it is the founder of
-       the channel. */
-    if (!silc_hash_table_count(channel->user_list))
-      chl->mode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+    if (server->server_type != SILC_ROUTER ||
+       sock->type == SILC_SOCKET_TYPE_ROUTER) {
+      /* If this is the first one on the channel then it is the founder of
+        the channel. This is done on normal server and on router if this
+        notify is coming from router */
+      if (!silc_hash_table_count(channel->user_list)) {
+       SILC_LOG_DEBUG(("Client %s is founder on channel",
+                       silc_id_render(chl->client->id, SILC_ID_CLIENT)));
+       chl->mode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+      }
+    }
 
     silc_hash_table_add(channel->user_list, client, chl);
     silc_hash_table_add(client->channels, channel, chl);
@@ -231,6 +236,13 @@ void silc_server_notify(SilcServer server,
     channel->user_count++;
     channel->disabled = FALSE;
 
+    /* Update statistics */
+    if (server->server_type == SILC_ROUTER) {
+      if (sock->type != SILC_SOCKET_TYPE_ROUTER)
+       server->stat.cell_chanclients++;
+      server->stat.chanclients++;
+    }
+
     break;
 
   case SILC_NOTIFY_TYPE_LEAVE:
@@ -253,6 +265,7 @@ void silc_server_notify(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->local_list, 
                                               channel_id, NULL);
       if (!channel) {
+       SILC_LOG_DEBUG(("Notify for unknown channel"));
        silc_free(channel_id);
        goto out;
       }
@@ -335,6 +348,7 @@ void silc_server_notify(SilcServer server,
       server->stat.cell_clients--;
     SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
     SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+    silc_schedule_task_del_by_context(server->schedule, client);
 
     /* Remove the client from all channels. */
     silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, FALSE);
@@ -344,6 +358,9 @@ void silc_server_notify(SilcServer server,
       silc_server_check_watcher_list(server, client, NULL,
                                     SILC_NOTIFY_TYPE_SIGNOFF);
 
+    /* Remove this client from watcher list if it is */
+    silc_server_del_from_watcher_list(server, client);
+
     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
     cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
     break;
@@ -359,22 +376,24 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+    client_id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
     if (!client_id)
       goto out;
 
     /* Get client entry */
-    client = silc_idlist_find_client_by_id(server->global_list, 
-                                          client_id, TRUE, &cache);
-    if (!client) {
-      client = silc_idlist_find_client_by_id(server->local_list, 
+    if (id_type == SILC_ID_CLIENT) {
+      client = silc_idlist_find_client_by_id(server->global_list, 
                                             client_id, TRUE, &cache);
       if (!client) {
-       silc_free(client_id);
-       goto out;
+       client = silc_idlist_find_client_by_id(server->local_list, 
+                                              client_id, TRUE, &cache);
+       if (!client) {
+         silc_free(client_id);
+         goto out;
+       }
       }
+      silc_free(client_id);
     }
-    silc_free(client_id);
 
     /* Get the topic */
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
@@ -397,22 +416,27 @@ void silc_server_notify(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->local_list, 
                                               channel_id, NULL);
       if (!channel) {
+       SILC_LOG_DEBUG(("Notify for unknown channel"));
        silc_free(channel_id);
        goto out;
       }
     }
 
-    if (channel->topic && !strcmp(channel->topic, tmp))
+    if (channel->topic && !strcmp(channel->topic, tmp)) {
+      SILC_LOG_DEBUG(("Topic is already set and same"));
       goto out;
+    }
 
-    /* Get user's channel entry and check that topic set is allowed. */
-    if (!silc_server_client_on_channel(client, channel, &chl))
-      goto out;
-    if (channel->mode & SILC_CHANNEL_MODE_TOPIC &&
-       !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
-       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
-      SILC_LOG_DEBUG(("Topic change is not allowed"));
-      goto out;
+    if (client) {
+      /* Get user's channel entry and check that topic set is allowed. */
+      if (!silc_server_client_on_channel(client, channel, &chl))
+       goto out;
+      if (channel->mode & SILC_CHANNEL_MODE_TOPIC &&
+         !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+         !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+       SILC_LOG_DEBUG(("Topic change is not allowed"));
+       goto out;
+      }
     }
 
     /* Change the topic */
@@ -420,7 +444,7 @@ void silc_server_notify(SilcServer server,
     channel->topic = strdup(tmp);
 
     /* Send the same notify to the channel */
-    silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
+    silc_server_packet_send_to_channel(server, NULL, channel, packet->type, 
                                       FALSE, packet->buffer->data, 
                                       packet->buffer->len, FALSE);
     silc_free(channel_id);
@@ -490,9 +514,9 @@ void silc_server_notify(SilcServer server,
     /* 
      * Distribute the notify to local clients on the channel
      */
-    
+
     SILC_LOG_DEBUG(("CMODE CHANGE notify"));
-      
+
     /* Get client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -530,6 +554,7 @@ void silc_server_notify(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->local_list, 
                                               channel_id, NULL);
       if (!channel) {
+       SILC_LOG_DEBUG(("Notify for unknown channel"));
        silc_free(channel_id);
        goto out;
       }
@@ -543,8 +568,42 @@ void silc_server_notify(SilcServer server,
     SILC_GET32_MSB(mode, tmp);
 
     /* Check if mode changed */
-    if (channel->mode == mode)
+    if (channel->mode == mode) {
+      SILC_LOG_DEBUG(("Mode is changed already"));
+
+      /* If this mode change has founder mode then we'll enforce the
+        change so that the server gets the real founder public key */
+      if (server->server_type != SILC_SERVER &&
+         sock != SILC_PRIMARY_ROUTE(server) &&
+         mode & SILC_CHANNEL_MODE_FOUNDER_AUTH && channel->founder_key) {
+       SILC_LOG_DEBUG(("Sending founder public key to server"));
+       silc_server_send_notify_cmode(server, sock, FALSE, channel,
+                                     channel->mode, server->id,
+                                     SILC_ID_SERVER, channel->cipher,
+                                     channel->hmac_name,
+                                     channel->passphrase,
+                                     channel->founder_key);
+      }
+
+      /* If we received same mode from our primary check whether founder
+        mode and key in the notify is set.  We update the founder key
+        here since we may have wrong one */
+      if (server->server_type == SILC_SERVER &&
+         sock == SILC_PRIMARY_ROUTE(server) &&
+         mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+       SILC_LOG_DEBUG(("Founder public key received from primary router"));
+       tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
+       if (!tmp)
+         break;
+
+       if (channel->founder_key)
+         silc_pkcs_public_key_free(channel->founder_key);
+       channel->founder_key = NULL;
+       silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key);
+      }
+
       break;
+    }
 
     /* Get user's channel entry and check that mode change is allowed */
     if (client) {
@@ -552,14 +611,52 @@ void silc_server_notify(SilcServer server,
        goto out;
       if (!silc_server_check_cmode_rights(server, channel, chl, mode)) {
        SILC_LOG_DEBUG(("CMODE change is not allowed"));
+       silc_server_send_notify_cmode(server, sock, FALSE, channel,
+                                     channel->mode, server->id,
+                                     SILC_ID_SERVER, channel->cipher,
+                                     channel->hmac_name,
+                                     channel->passphrase,
+                                     channel->founder_key);
+       goto out;
+      }
+    } else {
+      /* Assure that server is not removing founder mode from us */
+      if (server->server_type == SILC_ROUTER &&
+         sock != SILC_PRIMARY_ROUTE(server) &&
+         channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH &&
+         !(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
+       SILC_LOG_DEBUG(("Enforcing sender to change channel mode"));
+       silc_server_send_notify_cmode(server, sock, FALSE, channel,
+                                     channel->mode, server->id,
+                                     SILC_ID_SERVER, channel->cipher,
+                                     channel->hmac_name,
+                                     channel->passphrase,
+                                     channel->founder_key);
        goto out;
       }
-    }
 
-    /* Send the same notify to the channel */
-    silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
-                                      FALSE, packet->buffer->data, 
-                                      packet->buffer->len, FALSE);
+      /* If server is adding founder mode, check whether there is founder
+        on channel already and is not from this server */
+      if (server->server_type == SILC_ROUTER &&
+         sock != SILC_PRIMARY_ROUTE(server) &&
+         mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+       silc_hash_table_list(channel->user_list, &htl);
+       while (silc_hash_table_get(&htl, NULL, (void *)&chl))
+         if (chl->mode & SILC_CHANNEL_UMODE_CHANFO &&
+             chl->client->router != sock->user_data) {
+           SILC_LOG_DEBUG(("Enforcing sender to change channel mode"));
+           silc_server_send_notify_cmode(server, sock, FALSE, channel,
+                                         channel->mode, server->id,
+                                         SILC_ID_SERVER, channel->cipher,
+                                         channel->hmac_name,
+                                         channel->passphrase,
+                                         channel->founder_key);
+           silc_hash_table_list_reset(&htl);
+           goto out;
+         }
+       silc_hash_table_list_reset(&htl);
+      }
+    }
 
     /* If the channel had private keys set and the mode was removed then
        we must re-generate and re-distribute a new channel key */
@@ -646,6 +743,11 @@ void silc_server_notify(SilcServer server,
                                    channel->passphrase, NULL);
     }
 
+    /* Send the same notify to the channel */
+    silc_server_packet_send_to_channel(server, NULL, channel, packet->type, 
+                                      FALSE, packet->buffer->data, 
+                                      packet->buffer->len, FALSE);
+
     /* Change mode */
     channel->mode = mode;
 
@@ -664,9 +766,9 @@ void silc_server_notify(SilcServer server,
        */
       SilcChannelClientEntry chl2 = NULL;
       bool notify_sent = FALSE;
-      
+
       SILC_LOG_DEBUG(("CUMODE CHANGE notify"));
-      
+
       /* Get client ID */
       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
       if (!tmp)
@@ -704,6 +806,7 @@ void silc_server_notify(SilcServer server,
        channel = silc_idlist_find_channel_by_id(server->local_list, 
                                                 channel_id, NULL);
        if (!channel) {
+         SILC_LOG_DEBUG(("Notify for unknown channel"));
          silc_free(channel_id);
          goto out;
        }
@@ -744,7 +847,7 @@ void silc_server_notify(SilcServer server,
        if (!silc_server_client_on_channel(client, channel, &chl))
          goto out;
        
-       if (client != client2) {
+       if (client != client2 && server->server_type == SILC_ROUTER) {
          /* Sender must be operator */
          if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
              !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
@@ -752,7 +855,6 @@ void silc_server_notify(SilcServer server,
            goto out;
          }
 
-         /* Check that target is on channel */
          if (!silc_server_client_on_channel(client2, channel, &chl))
            goto out;
 
@@ -764,20 +866,28 @@ void silc_server_notify(SilcServer server,
        }
       }
 
+      /* Get target channel user entry */
+      if (!silc_server_client_on_channel(client2, channel, &chl))
+       goto out;
+
+      if (server->server_type == SILC_SERVER && chl->mode == mode) {
+       SILC_LOG_DEBUG(("Mode is changed already"));
+       break;
+      }
+
       if (mode & SILC_CHANNEL_UMODE_CHANFO &&
-         !(chl->mode & SILC_CHANNEL_UMODE_CHANFO) && 
-         server->server_type == SILC_ROUTER) {
-       /* Check whether this client is allowed to be channel founder on
-          this channel. */
+         !(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
+         server->server_type == SILC_ROUTER &&
+         sock != SILC_PRIMARY_ROUTE(server)) {
        SilcPublicKey founder_key = NULL;
 
        /* If channel doesn't have founder auth mode then it's impossible
           that someone would be getting founder rights with CUMODE command.
           In that case there already either is founder or there isn't
           founder at all on the channel. */
-       if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
+       if (client && !(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
          /* Force the mode to not have founder mode */
-         mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+         chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
          silc_server_force_cumode_change(server, sock, channel, chl, mode);
          notify_sent = TRUE;
          break;
@@ -788,9 +898,20 @@ void silc_server_notify(SilcServer server,
        silc_hash_table_list(channel->user_list, &htl);
        while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
          if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
-           mode &= ~SILC_CHANNEL_UMODE_CHANFO;
-           silc_server_force_cumode_change(server, sock, channel, chl, mode);
-           notify_sent = TRUE;
+           /* If the founder on the channel is not the one whom has set
+              the founder mode, then it's possible that this CUMODE_CHANGE
+              is correct.  Due to netsplits it's possible that this
+              situation happens. */
+           if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
+               (channel->founder_key && chl2->client->data.public_key &&
+                silc_pkcs_public_key_compare(
+                                       channel->founder_key,
+                                       chl2->client->data.public_key))) {
+             chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+             silc_server_force_cumode_change(server, sock, channel,
+                                             chl, mode);
+             notify_sent = TRUE;
+           }
            break;
          }
        silc_hash_table_list_reset(&htl);
@@ -801,46 +922,67 @@ void silc_server_notify(SilcServer server,
           is set on the channel now check whether this is the client that
           originally set the mode. */
 
-       /* Get public key that must be present in notify */
-       tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
-       if (!tmp || !silc_pkcs_public_key_decode(tmp, tmp_len,
-                                                &founder_key)) {
-         mode &= ~SILC_CHANNEL_UMODE_CHANFO;
-         silc_server_force_cumode_change(server, sock, channel, chl, mode);
-         notify_sent = TRUE;
-         break;
-       }
+       if (channel->founder_key) {
+         /* Get public key that must be present in notify */
+         tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+         if (!tmp || !silc_pkcs_public_key_decode(tmp, tmp_len,
+                                                  &founder_key)) {
+           chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+           silc_server_force_cumode_change(server, sock, channel, chl, mode);
+           notify_sent = TRUE;
+           break;
+         }
 
-       /* Now match the public key we have cached and public key sent.
-          They must match. */
-       if (client && client->data.public_key && 
-           !silc_pkcs_public_key_compare(channel->founder_key,
-                                         client->data.public_key)) {
-         mode &= ~SILC_CHANNEL_UMODE_CHANFO;
-         silc_server_force_cumode_change(server, sock, channel, chl, mode);
-         notify_sent = TRUE;
-         break;
-       }
-       if (!silc_pkcs_public_key_compare(channel->founder_key,
-                                         founder_key)) {
-         mode &= ~SILC_CHANNEL_UMODE_CHANFO;
-         silc_server_force_cumode_change(server, sock, channel, chl, mode);
-         notify_sent = TRUE;
-         break;
+         /* Now match the public key we have cached and public key sent.
+            They must match. */
+         if (client && client->data.public_key && 
+             !silc_pkcs_public_key_compare(channel->founder_key,
+                                           client->data.public_key)) {
+           chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+           silc_server_force_cumode_change(server, sock, channel, chl, mode);
+           notify_sent = TRUE;
+           break;
+         }
+         if (!silc_pkcs_public_key_compare(channel->founder_key,
+                                           founder_key)) {
+           chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+           silc_server_force_cumode_change(server, sock, channel, chl, mode);
+           notify_sent = TRUE;
+           break;
+         }
        }
 
+       /* There cannot be anyone else as founder on the channel now.  This
+          client is definitely the founder due to this authentication */
+       silc_hash_table_list(channel->user_list, &htl);
+       while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
+         if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
+           chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+           silc_server_force_cumode_change(server, NULL, channel, chl2,
+                                           chl2->mode);
+           break;
+         }
+       silc_hash_table_list_reset(&htl);
+
        if (founder_key)
          silc_pkcs_public_key_free(founder_key);
       }
 
-      SILC_LOG_DEBUG(("Changing the channel user mode"));
+      if (server->server_type != SILC_SERVER && chl->mode == mode) {
+       SILC_LOG_DEBUG(("Mode is changed already"));
+       break;
+      }
+
+      SILC_LOG_DEBUG(("Changing %s channel user mode",
+                     chl->client->nickname ? chl->client->nickname :
+                     (unsigned char *)""));
 
       /* Change the mode */
       chl->mode = mode;
 
       /* Send the same notify to the channel */
       if (!notify_sent)
-       silc_server_packet_send_to_channel(server, sock, channel, 
+       silc_server_packet_send_to_channel(server, NULL, channel, 
                                           packet->type, 
                                           FALSE, packet->buffer->data, 
                                           packet->buffer->len, FALSE);
@@ -871,6 +1013,7 @@ void silc_server_notify(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->local_list, 
                                               channel_id, NULL);
       if (!channel) {
+       SILC_LOG_DEBUG(("Notify for unknown channel"));
        silc_free(channel_id);
        goto out;
       }
@@ -978,6 +1121,7 @@ void silc_server_notify(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->global_list, 
                                               channel_id, NULL);
       if (!channel) {
+       SILC_LOG_DEBUG(("Notify for unknown channel"));
        silc_free(channel_id);
        goto out;
       }
@@ -1023,6 +1167,13 @@ void silc_server_notify(SilcServer server,
       /* Re-announce our clients on the channel as the ID has changed now */
       silc_server_announce_get_channel_users(server, channel, &modes, &users,
                                             &users_modes);
+      if (users) {
+       silc_buffer_push(users, users->data - users->head);
+       silc_server_packet_send(server, sock,
+                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                               users->data, users->len, FALSE);
+       silc_buffer_free(users);
+      }
       if (modes) {
        silc_buffer_push(modes, modes->data - modes->head);
        silc_server_packet_send_dest(server, sock,
@@ -1031,13 +1182,6 @@ void silc_server_notify(SilcServer server,
                                     modes->data, modes->len, FALSE);
        silc_buffer_free(modes);
       }
-      if (users) {
-       silc_buffer_push(users, users->data - users->head);
-       silc_server_packet_send(server, sock,
-                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
-                               users->data, users->len, FALSE);
-       silc_buffer_free(users);
-      }
       if (users_modes) {
        silc_buffer_push(users_modes, users_modes->data - users_modes->head);
        silc_server_packet_send_dest(server, sock,
@@ -1053,7 +1197,7 @@ void silc_server_notify(SilcServer server,
        silc_server_send_notify_topic_set(server, sock,
                                          server->server_type == SILC_ROUTER ?
                                          TRUE : FALSE, channel, 
-                                         channel->id, SILC_ID_CHANNEL,
+                                         server->id, SILC_ID_SERVER,
                                          channel->topic);
       }
     }
@@ -1150,15 +1294,22 @@ void silc_server_notify(SilcServer server,
     }
     silc_free(server_id);
 
+    /* Sending SERVER_SIGNOFF is not right way to signoff local connection */
+    if (SILC_IS_LOCAL(server_entry))
+      break;
+
     /* Free all client entries that this server owns as they will
        become invalid now as well. */
     silc_server_remove_clients_by_server(server, server_entry, TRUE);
+    silc_server_backup_del(server, server_entry);
 
     /* Remove the server entry */
     silc_idlist_del_server(local ? server->local_list :
                           server->global_list, server_entry);
 
-    /* XXX update statistics */
+    /* Update statistics */
+    if (server->server_type == SILC_ROUTER)
+      server->stat.servers--;
 
     break;
 
@@ -1183,6 +1334,7 @@ void silc_server_notify(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->local_list, 
                                               channel_id, NULL);
       if (!channel) {
+       SILC_LOG_DEBUG(("Notify for unknown channel"));
        silc_free(channel_id);
        goto out;
       }
@@ -1276,10 +1428,10 @@ void silc_server_notify(SilcServer server,
 
       /* If the the client is not in local list we check global list */
       client = silc_idlist_find_client_by_id(server->global_list, 
-                                            client_id, TRUE, NULL);
+                                            client_id, TRUE, &cache);
       if (!client) {
        client = silc_idlist_find_client_by_id(server->local_list, 
-                                              client_id, TRUE, NULL);
+                                              client_id, TRUE, &cache);
        if (!client) {
          silc_free(client_id);
          goto out;
@@ -1323,7 +1475,8 @@ void silc_server_notify(SilcServer server,
          silc_free(client_id);
 
          /* Killer must be router operator */
-         if (!(client2->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+         if (server->server_type != SILC_SERVER &&
+             !(client2->mode & SILC_UMODE_ROUTER_OPERATOR)) {
            SILC_LOG_DEBUG(("Killing is not allowed"));
            goto out;
          }
@@ -1342,10 +1495,25 @@ void silc_server_notify(SilcServer server,
                                       FALSE);
 
       /* Check if anyone is watching this nickname */
-      if (server->server_type == SILC_ROUTER)
-       silc_server_check_watcher_list(server, client, NULL,
-                                      SILC_NOTIFY_TYPE_KILLED);
+      silc_server_check_watcher_list(server, client, NULL,
+                                    SILC_NOTIFY_TYPE_KILLED);
 
+      /* Update statistics */
+      server->stat.clients--;
+      if (server->stat.cell_clients)
+       server->stat.cell_clients--;
+      SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+      SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
+      if (SILC_IS_LOCAL(client)) {
+       server->stat.my_clients--;
+       silc_schedule_task_del_by_context(server->schedule, client);
+       silc_idlist_del_data(client);
+       client->mode = 0;
+      }
+
+      client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+      cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
       break;
     }
 
@@ -1383,16 +1551,28 @@ void silc_server_notify(SilcServer server,
       goto out;
     SILC_GET32_MSB(mode, tmp);
 
-    /* Check that mode changing is allowed. */
-    if (!silc_server_check_umode_rights(server, client, mode)) {
-      SILC_LOG_DEBUG(("UMODE change is not allowed"));
-      goto out;
-    }
-
     /* Remove internal resumed flag if client is marked detached now */
     if (mode & SILC_UMODE_DETACHED)
       client->data.status &= ~SILC_IDLIST_STATUS_RESUMED;
 
+    /* Update statistics */
+    if (server->server_type == SILC_ROUTER) {
+      if (mode & SILC_UMODE_GONE) {
+       if (!(client->mode & SILC_UMODE_GONE))
+         server->stat.aways++;
+      } else {
+       if (client->mode & SILC_UMODE_GONE)
+         server->stat.aways--;
+      }
+      if (mode & SILC_UMODE_DETACHED) {
+       if (!(client->mode & SILC_UMODE_DETACHED))
+         server->stat.detached++;
+      } else {
+       if (client->mode & SILC_UMODE_DETACHED)
+         server->stat.detached--;
+      }
+    }
+
     /* Change the mode */
     client->mode = mode;
 
@@ -1425,6 +1605,7 @@ void silc_server_notify(SilcServer server,
       channel = silc_idlist_find_channel_by_id(server->local_list, 
                                               channel_id, NULL);
       if (!channel) {
+       SILC_LOG_DEBUG(("Notify for unknown channel"));
        silc_free(channel_id);
        goto out;
       }
@@ -1850,6 +2031,10 @@ void silc_server_channel_message(SilcServer server,
       SILC_LOG_DEBUG(("Channel is silenced from operators"));
       goto out;
     }
+    if (chl->mode & SILC_CHANNEL_UMODE_QUIET) {
+      SILC_LOG_DEBUG(("Sender is quieted on the channel"));
+      goto out;
+    }
 
     /* If the packet is coming from router, but the client entry is local 
        entry to us then some router is rerouting this to us and it is not 
@@ -2100,12 +2285,18 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                   client_id, client, 0, NULL);
 
   /* Notify our router about new client on the SILC network */
-  if (!server->standalone)
-    silc_server_send_new_id(server, (SilcSocketConnection) 
-                           server->router->connection, 
-                           server->server_type == SILC_ROUTER ? TRUE : FALSE,
-                           client->id, SILC_ID_CLIENT, id_len);
-  
+  silc_server_send_new_id(server, SILC_PRIMARY_ROUTE(server),
+                         SILC_BROADCAST(server), client->id,
+                         SILC_ID_CLIENT, id_len);
+
+  /* Distribute to backup routers */
+  if (server->server_type == SILC_ROUTER) {
+    SilcBuffer idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0,
+                           idp->data, idp->len, FALSE, TRUE);
+    silc_buffer_free(idp);
+  }
+
   /* Send the new client ID to the client. */
   silc_server_send_new_id(server, sock, FALSE, client->id, SILC_ID_CLIENT,
                          silc_id_get_len(client->id, SILC_ID_CLIENT));
@@ -2253,13 +2444,21 @@ SilcServerEntry silc_server_new_server(SilcServer server,
      to our router. If we are normal server we won't send anything
      since this connection must be our router connection. */
   if (server->server_type == SILC_ROUTER && !server->standalone &&
-      server->router->connection != sock)
-    silc_server_send_new_id(server, server->router->connection,
+      SILC_PRIMARY_ROUTE(server) != sock)
+    silc_server_send_new_id(server, SILC_PRIMARY_ROUTE(server),
                            TRUE, new_server->id, SILC_ID_SERVER, 
                            silc_id_get_len(server_id, SILC_ID_SERVER));
 
-  if (server->server_type == SILC_ROUTER)
+  if (server->server_type == SILC_ROUTER) {
+    /* Distribute to backup routers */
+    SilcBuffer idp = silc_id_payload_encode(new_server->id, SILC_ID_SERVER);
+    silc_server_backup_send(server, NULL, SILC_PACKET_NEW_ID, 0,
+                           idp->data, idp->len, FALSE, TRUE);
+    silc_buffer_free(idp);
+
+    /* Statistics */
     server->stat.cell_servers++;
+  }
 
   /* Check whether this router connection has been replaced by an
      backup router. If it has been then we'll disable the server and will
@@ -2291,6 +2490,12 @@ SilcServerEntry silc_server_new_server(SilcServer server,
       silc_server_announce_clients(server, 0, sock);
       silc_server_announce_channels(server, 0, sock);
     }
+
+    /* By default the servers connected to backup router are disabled
+       until backup router has become the primary */
+    if (server->server_type == SILC_BACKUP_ROUTER &&
+       sock->type == SILC_SOCKET_TYPE_SERVER)
+      idata->status |= SILC_IDLIST_STATUS_DISABLED;
   }
 
   return new_server;
@@ -2349,7 +2554,7 @@ static void silc_server_new_id_real(SilcServer server,
        id_type == SILC_ID_SERVER && 
        server->id_entry->server_type != SILC_BACKUP_ROUTER) {
       id_list = server->global_list;
-      router_sock = server->router ? server->router->connection : sock;
+      router_sock = server->router ? SILC_PRIMARY_ROUTE(server) : sock;
     }
   } else {
     void *sender_id = silc_id_str2id(packet->src_id, packet->src_id_len,
@@ -2478,11 +2683,11 @@ static void silc_server_new_id_real(SilcServer server,
 
   /* If the sender of this packet is server and we are router we need to
      broadcast this packet to other routers in the network. */
-  if (broadcast && !server->standalone && server->server_type == SILC_ROUTER &&
+  if (broadcast && server->server_type == SILC_ROUTER &&
       sock->type == SILC_SOCKET_TYPE_SERVER &&
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received New ID packet"));
-    silc_server_packet_send(server, server->router->connection,
+    silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            packet->type, 
                            packet->flags | SILC_PACKET_FLAG_BROADCAST,
                            buffer->data, buffer->len, FALSE);
@@ -2525,14 +2730,15 @@ void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
   /* If the sender of this packet is server and we are router we need to
      broadcast this packet to other routers in the network. Broadcast
      this list packet instead of multiple New ID packets. */
-  if (!server->standalone && server->server_type == SILC_ROUTER &&
+  if (server->server_type == SILC_ROUTER &&
       sock->type == SILC_SOCKET_TYPE_SERVER &&
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received New ID List packet"));
-    silc_server_packet_send(server, server->router->connection,
+    silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            packet->type, 
                            packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           packet->buffer->data, packet->buffer->len, FALSE);
+                           packet->buffer->data, 
+                           packet->buffer->len, FALSE);
     silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
                            packet->type, packet->flags,
                            packet->buffer->data, packet->buffer->len, 
@@ -2589,12 +2795,9 @@ void silc_server_new_channel(SilcServer server,
   SilcUInt32 name_len;
   unsigned char *id;
   SilcUInt32 id_len;
-  SilcUInt32 mode;
   SilcServerEntry server_entry;
   SilcChannelEntry channel;
 
-  SILC_LOG_DEBUG(("Processing New Channel"));
-
   if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
       packet->src_id_type != SILC_ID_SERVER ||
       server->server_type == SILC_SERVER)
@@ -2666,6 +2869,8 @@ void silc_server_new_channel(SilcServer server,
     /* If the channel does not exist, then create it. This creates a new
        key to the channel as well that we will send to the server. */
     if (!channel) {
+      SILC_LOG_DEBUG(("Channel is new to us"));
+
       /* The protocol says that the Channel ID's IP address must be based
         on the router's IP address.  Check whether the ID is based in our
         IP and if it is not then create a new ID and enforce the server
@@ -2693,12 +2898,7 @@ void silc_server_new_channel(SilcServer server,
        return;
       }
       channel->disabled = TRUE;
-
-#if 0
-      /* CMODE change notify is expected */
-      /* Get the mode and set it to the channel */
       channel->mode = silc_channel_get_mode(payload);
-#endif
 
       /* Send the new channel key to the server */
       id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
@@ -2712,21 +2912,28 @@ void silc_server_new_channel(SilcServer server,
       silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
                              chk->data, chk->len, FALSE);
       silc_buffer_free(chk);
-
     } else {
       /* The channel exist by that name, check whether the ID's match.
         If they don't then we'll force the server to use the ID we have.
         We also create a new key for the channel. */
       SilcBuffer modes = NULL, users = NULL, users_modes = NULL;
 
+      SILC_LOG_DEBUG(("Channel already exists"));
+
       if (!SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
        /* They don't match, send CHANNEL_CHANGE notify to the server to
           force the ID change. */
        SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
        silc_server_send_notify_channel_change(server, sock, FALSE, 
                                               channel_id, channel->id);
+
+       /* Wait that server re-announces this channel */
+       return;
       }
 
+#if 0 /* We will announce our CMODE anyway for this channel, so no need
+        to check it (implicit enforce). */
+
       /* If the mode is different from what we have then enforce the
         mode change. */
       mode = silc_channel_get_mode(payload);
@@ -2739,6 +2946,7 @@ void silc_server_new_channel(SilcServer server,
                                      channel->passphrase,
                                      channel->founder_key);
       }
+#endif
 
       /* Create new key for the channel and send it to the server and
         everybody else possibly on the channel. */
@@ -2767,11 +2975,22 @@ void silc_server_new_channel(SilcServer server,
 
       silc_free(channel_id);
 
+      /* Update statistics */
+      server->stat.channels++;
+      server->stat.cell_channels++;
+
       /* Since the channel is coming from server and we also know about it
         then send the JOIN notify to the server so that it see's our
         users on the channel "joining" the channel. */
       silc_server_announce_get_channel_users(server, channel, &modes, &users,
                                             &users_modes);
+      if (users) {
+       silc_buffer_push(users, users->data - users->head);
+       silc_server_packet_send(server, sock,
+                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                               users->data, users->len, FALSE);
+       silc_buffer_free(users);
+      }
       if (modes) {
        silc_buffer_push(modes, modes->data - modes->head);
        silc_server_packet_send_dest(server, sock,
@@ -2780,13 +2999,6 @@ void silc_server_new_channel(SilcServer server,
                                     modes->data, modes->len, FALSE);
        silc_buffer_free(modes);
       }
-      if (users) {
-       silc_buffer_push(users, users->data - users->head);
-       silc_server_packet_send(server, sock,
-                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
-                               users->data, users->len, FALSE);
-       silc_buffer_free(users);
-      }
       if (users_modes) {
        silc_buffer_push(users_modes, users_modes->data - users_modes->head);
        silc_server_packet_send_dest(server, sock,
@@ -2796,6 +3008,13 @@ void silc_server_new_channel(SilcServer server,
                                     users_modes->len, FALSE);
        silc_buffer_free(users_modes);
       }
+      if (channel->topic) {
+       silc_server_send_notify_topic_set(server, sock,
+                                         server->server_type == SILC_ROUTER ?
+                                         TRUE : FALSE, channel, 
+                                         server->id, SILC_ID_SERVER,
+                                         channel->topic);
+      }
     }
   }
 
@@ -2823,14 +3042,15 @@ void silc_server_new_channel_list(SilcServer server,
   /* If the sender of this packet is server and we are router we need to
      broadcast this packet to other routers in the network. Broadcast
      this list packet instead of multiple New Channel packets. */
-  if (!server->standalone && server->server_type == SILC_ROUTER &&
+  if (server->server_type == SILC_ROUTER &&
       sock->type == SILC_SOCKET_TYPE_SERVER &&
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received New Channel List packet"));
-    silc_server_packet_send(server, server->router->connection,
+    silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                            packet->type, 
                            packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           packet->buffer->data, packet->buffer->len, FALSE);
+                           packet->buffer->data, 
+                           packet->buffer->len, FALSE);
     silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
                            packet->type, packet->flags,
                            packet->buffer->data, packet->buffer->len, 
@@ -2928,10 +3148,10 @@ void silc_server_connection_auth_request(SilcServer server,
   int ret;
   SilcAuthMethod auth_meth = SILC_AUTH_NONE;
 
-  SILC_LOG_DEBUG(("Start"));
-
-  if (packet->src_id_type && packet->src_id_type != SILC_ID_CLIENT)
+  if (packet->src_id_type && packet->src_id_type != SILC_ID_CLIENT) {
+    SILC_LOG_DEBUG(("Request not from client"));
     return;
+  }
 
   /* Parse the payload */
   ret = silc_buffer_unformat(packet->buffer,
@@ -2959,6 +3179,11 @@ void silc_server_connection_auth_request(SilcServer server,
       auth_meth = SILC_AUTH_PUBLIC_KEY;
   }
 
+  SILC_LOG_DEBUG(("Authentication method is [%s]",
+                 (auth_meth == SILC_AUTH_NONE ? "None" :
+                  auth_meth == SILC_AUTH_PASSWORD ? "Passphrase" :
+                  "Digital signatures")));
+
   /* Send it back to the client */
   silc_server_send_connection_auth_request(server, sock, conn_type, auth_meth);
 }
@@ -3052,6 +3277,8 @@ SILC_SERVER_CMD_FUNC(resume_resolve)
     silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  "Resuming not possible");
+    if (sock->user_data)
+      silc_server_free_sock_user_data(server, sock, NULL);
     goto out;
   }
 
@@ -3068,6 +3295,8 @@ SILC_SERVER_CMD_FUNC(resume_resolve)
        silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                      "Resuming not possible");
+       if (sock->user_data)
+         silc_server_free_sock_user_data(server, sock, NULL);
        goto out;
       }
     }
@@ -3078,6 +3307,8 @@ SILC_SERVER_CMD_FUNC(resume_resolve)
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    "Resuming not possible");
+      if (sock->user_data)
+       silc_server_free_sock_user_data(server, sock, NULL);
       goto out;
     }
   }
@@ -3114,8 +3345,6 @@ void silc_server_resume_client(SilcServer server,
   SilcChannelClientEntry chl;
   SilcServerResumeResolve r;
 
-  SILC_LOG_DEBUG(("Start"));
-
   ret = silc_buffer_unformat(buffer,
                             SILC_STR_UI16_NSTRING(&id_string, &id_len),
                             SILC_STR_END);
@@ -3140,6 +3369,9 @@ void silc_server_resume_client(SilcServer server,
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    "Resuming not possible");
+      if (sock->user_data)
+       silc_server_free_sock_user_data(server, sock, NULL);
+      silc_free(client_id);
       return;
     }
 
@@ -3161,7 +3393,7 @@ void silc_server_resume_client(SilcServer server,
        r->server = server;
        r->sock = silc_socket_dup(sock);
        r->packet = silc_packet_context_dup(packet);
-       r->data = silc_id_dup(client_id, SILC_ID_CLIENT);
+       r->data = client_id;
        silc_server_command_pending(server, SILC_COMMAND_WHOIS,
                                    server->cmd_ident,
                                    silc_server_command_resume_resolve, r);
@@ -3171,6 +3403,9 @@ void silc_server_resume_client(SilcServer server,
        silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                      "Resuming not possible");
+       if (sock->user_data)
+         silc_server_free_sock_user_data(server, sock, NULL);
+       silc_free(client_id);
       }
       return;
     }
@@ -3195,7 +3430,7 @@ void silc_server_resume_client(SilcServer server,
        r->server = server;
        r->sock = silc_socket_dup(sock);
        r->packet = silc_packet_context_dup(packet);
-       r->data = silc_id_dup(client_id, SILC_ID_CLIENT);
+       r->data = client_id;
        silc_server_command_pending(server, SILC_COMMAND_WHOIS,
                                    server->cmd_ident,
                                    silc_server_command_resume_resolve, r);
@@ -3207,6 +3442,9 @@ void silc_server_resume_client(SilcServer server,
        silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                      "Resuming not possible");
+       if (sock->user_data)
+         silc_server_free_sock_user_data(server, sock, NULL);
+       silc_free(client_id);
        return;
       }
     }
@@ -3215,9 +3453,14 @@ void silc_server_resume_client(SilcServer server,
        resolve it first. */
     if (!detached_client->data.public_key) {
       if (server->server_type == SILC_SERVER && server->standalone) {
+       SILC_LOG_ERROR(("Detached client's public key not present, "
+                       "closing connection"));
        silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                      "Resuming not possible");
+       if (sock->user_data)
+         silc_server_free_sock_user_data(server, sock, NULL);
+       silc_free(client_id);
       } else {
        /* We must retrieve the detached client's public key by sending
           GETKEY command. Reprocess this packet after receiving the key */
@@ -3228,13 +3471,15 @@ void silc_server_resume_client(SilcServer server,
        SILC_LOG_DEBUG(("Resolving client public key"));
 
        silc_server_send_command(server, dest_sock ? dest_sock : 
-                                server->router->connection,
+                                SILC_PRIMARY_ROUTE(server),
                                 SILC_COMMAND_GETKEY, ++server->cmd_ident,
                                 1, 1, idp->data, idp->len);
 
        r = silc_calloc(1, sizeof(*r));
-       if (!r)
+       if (!r) {
+         silc_free(client_id);
          return;
+       }
 
        r->server = server;
        r->sock = silc_socket_dup(sock);
@@ -3245,14 +3490,20 @@ void silc_server_resume_client(SilcServer server,
 
        silc_buffer_free(idp);
       }
+      silc_free(client_id);
       return;
     } else if (!silc_pkcs_public_key_compare(detached_client->data.public_key,
                                             idata->public_key)) {
       /* We require that the connection and resuming authentication data
         must be using same key pair. */
+      SILC_LOG_ERROR(("Resuming attempted with wrong public key, "
+                     "closing connection"));
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    "Resuming not possible");
+      if (sock->user_data)
+       silc_server_free_sock_user_data(server, sock, NULL);
+      silc_free(client_id);
       return;
     }
 
@@ -3268,6 +3519,9 @@ void silc_server_resume_client(SilcServer server,
       silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    "Resuming not possible");
+      if (sock->user_data)
+       silc_server_free_sock_user_data(server, sock, NULL);
+      silc_free(client_id);
       return;
     }
 
@@ -3283,6 +3537,7 @@ void silc_server_resume_client(SilcServer server,
     detached_client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED;
     detached_client->mode &= ~SILC_UMODE_DETACHED;
+    server->stat.my_detached--;
 
     /* Send the RESUME_CLIENT packet to our primary router so that others
        know this client isn't detached anymore. */
@@ -3293,10 +3548,9 @@ void silc_server_resume_client(SilcServer server,
                       SILC_STR_END);
 
     /* Send to primary router */
-    if (!server->standalone)
-      silc_server_packet_send(server, server->router->connection,
-                             SILC_PACKET_RESUME_CLIENT, 0, 
-                             buf->data, buf->len, TRUE);
+    silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
+                           SILC_PACKET_RESUME_CLIENT, 0, 
+                           buf->data, buf->len, TRUE);
 
     /* As router we must deliver this packet directly to the original
        server whom this client was earlier. */
@@ -3314,11 +3568,13 @@ void silc_server_resume_client(SilcServer server,
     server->stat.clients--;
     if (server->stat.cell_clients)
       server->stat.cell_clients--;
+    silc_server_del_from_watcher_list(server, client);
     silc_idlist_del_client(server->local_list, client);
     client = detached_client;
 
     /* If the ID is not based in our ID then change it */
     if (!SILC_ID_COMPARE(client->id, server->id, server->id->ip.data_len)) {
+      silc_free(client_id);
       while (!silc_id_create_client_id(server, server->id, server->rng, 
                                       server->md5hash, client->nickname, 
                                       &client_id)) {
@@ -3326,6 +3582,8 @@ void silc_server_resume_client(SilcServer server,
        if (nickfail > 9) {
          silc_server_disconnect_remote(server, sock, 
                                        SILC_STATUS_ERR_BAD_NICKNAME, NULL);
+         if (sock->user_data)
+           silc_server_free_sock_user_data(server, sock, NULL);
          return;
        }
        snprintf(&client->nickname[strlen(client->nickname) - 1], 1, 
@@ -3336,10 +3594,10 @@ void silc_server_resume_client(SilcServer server,
 
     if (nick_change) {
       /* Notify about Client ID change, nickname doesn't actually change. */
-      if (!server->standalone)
-       silc_server_send_notify_nick_change(server, server->router->connection,
-                                           FALSE, client->id, client_id,
-                                           client->nickname);
+      silc_server_send_notify_nick_change(server, SILC_PRIMARY_ROUTE(server),
+                                         SILC_BROADCAST(server),
+                                         client->id, client_id,
+                                         client->nickname);
     }
 
     /* Resolve users on those channels that client has joined but we
@@ -3351,7 +3609,7 @@ void silc_server_resume_client(SilcServer server,
        SILC_LOG_DEBUG(("Resolving users for %s channel", 
                        channel->channel_name));
        if (channel->disabled || !channel->users_resolved) {
-         silc_server_send_command(server, server->router->connection,
+         silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
                                   SILC_COMMAND_USERS, ++server->cmd_ident,
                                   1, 2, channel->channel_name,
                                   strlen(channel->channel_name));
@@ -3423,9 +3681,8 @@ void silc_server_resume_client(SilcServer server,
       silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
                              keyp->data, keyp->len, FALSE);
 
-      if (created && server->server_type == SILC_SERVER && 
-         !server->standalone)
-       silc_server_packet_send(server, server->router->connection, 
+      if (created && server->server_type == SILC_SERVER)
+       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server), 
                                SILC_PACKET_CHANNEL_KEY, 0, 
                                keyp->data, keyp->len, FALSE);
 
@@ -3439,8 +3696,10 @@ void silc_server_resume_client(SilcServer server,
     SilcServerEntry server_entry;
     SilcServerID *server_id;
 
-    if (!client_id)
+    if (!client_id) {
+      SILC_LOG_DEBUG(("Malformed resuming packet"));
       return;
+    }
 
     /* Get entry to the client, and resolve it if we don't have it. */
     detached_client = silc_idlist_find_client_by_id(server->local_list, 
@@ -3448,8 +3707,11 @@ void silc_server_resume_client(SilcServer server,
     if (!detached_client) {
       detached_client = silc_idlist_find_client_by_id(server->global_list,
                                                      client_id, TRUE, NULL);
-      if (!detached_client)
+      if (!detached_client) {
+       SILC_LOG_DEBUG(("Resuming client is unknown"));
+       silc_free(client_id);
        return;
+      }
     }
 
     /* Check that the client has not been resumed already because it is
@@ -3460,14 +3722,19 @@ void silc_server_resume_client(SilcServer server,
       /* The client is clearly attempting to resume more than once and
         perhaps playing around by resuming from several different places
         at the same time. */
+      SILC_LOG_DEBUG(("Attempting to re-resume client, killing both"));
       silc_server_kill_client(server, detached_client, NULL,
                              server->id, SILC_ID_SERVER);
+      silc_free(client_id);
       return;
     }
 
     /* Check whether client is detached at all */
-    if (!(detached_client->mode & SILC_UMODE_DETACHED))
+    if (!(detached_client->mode & SILC_UMODE_DETACHED)) {
+      SILC_LOG_DEBUG(("Client is not detached"));
+      silc_free(client_id);
       return;
+    }
 
     /* Client is detached, and now it is resumed.  Remove the detached
        mode and mark that it is resumed. */
@@ -3477,8 +3744,10 @@ void silc_server_resume_client(SilcServer server,
     /* Get the new owner of the resumed client */
     server_id = silc_id_str2id(packet->src_id, packet->src_id_len,
                               packet->src_id_type);
-    if (!server_id)
+    if (!server_id) {
+      silc_free(client_id);
       return;
+    }
 
     /* Get server entry */
     server_entry = silc_idlist_find_server_by_id(server->global_list, 
@@ -3490,6 +3759,7 @@ void silc_server_resume_client(SilcServer server,
       local = FALSE;
       if (!server_entry) {
        silc_free(server_id);
+       silc_free(client_id);
        return;
       }
     }
@@ -3511,6 +3781,7 @@ void silc_server_resume_client(SilcServer server,
                     server->global_list->clients, 
                     detached_client->nickname,
                     detached_client->id, detached_client, FALSE, NULL);
+    detached_client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
 
     /* Change the owner of the client if needed */
     if (detached_client->router != server_entry)
@@ -3529,11 +3800,11 @@ void silc_server_resume_client(SilcServer server,
 
     /* If the sender of this packet is server and we are router we need to
        broadcast this packet to other routers in the network. */
-    if (!server->standalone && server->server_type == SILC_ROUTER &&
+    if (server->server_type == SILC_ROUTER &&
        sock->type == SILC_SOCKET_TYPE_SERVER &&
        !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
       SILC_LOG_DEBUG(("Broadcasting received Resume Client packet"));
-      silc_server_packet_send(server, server->router->connection,
+      silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              packet->type, 
                              packet->flags | SILC_PACKET_FLAG_BROADCAST,
                              buffer->data, buffer->len, FALSE);