Send SERVER_SIGNOFF to local backup routers from primary router.
[silc.git] / apps / silcd / packet_receive.c
index f5b28e6100a44ab2ce7eaa220b5ce0808ea72892..b3828beb1a4b392db9fdfa1f1ea8c17b1f3904de 100644 (file)
@@ -43,7 +43,7 @@ void silc_server_notify(SilcServer server,
   SilcClientEntry client = NULL, client2 = NULL;
   SilcServerEntry server_entry = NULL;
   SilcChannelClientEntry chl;
-  SilcIDCacheEntry cache;
+  SilcIDCacheEntry cache = NULL;
   SilcHashTableList htl;
   SilcUInt32 mode;
   unsigned char *tmp;
@@ -94,27 +94,25 @@ void silc_server_notify(SilcServer server,
       if (!channel_id)
        goto out;
 
-      if (!server->standalone)
-       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);
-      silc_server_backup_send_dest(server, (SilcServerEntry)sock->user_data, 
+      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);
+      silc_server_backup_send_dest(server, sock->user_data, 
                                   packet->type, packet->flags,
                                   channel_id, SILC_ID_CHANNEL,
                                   packet->buffer->data, packet->buffer->len, 
                                   FALSE, TRUE);
     } else {
       /* Packet is destined to client or server */
-      if (!server->standalone)
-       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server), 
-                               packet->type,
-                               packet->flags | SILC_PACKET_FLAG_BROADCAST, 
-                               packet->buffer->data, packet->buffer->len, 
-                               FALSE);
-      silc_server_backup_send(server, (SilcServerEntry)sock->user_data,
+      silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server), 
+                             packet->type,
+                             packet->flags | SILC_PACKET_FLAG_BROADCAST, 
+                             packet->buffer->data, packet->buffer->len, 
+                             FALSE);
+      silc_server_backup_send(server, sock->user_data,
                              packet->type, packet->flags,
                              packet->buffer->data, packet->buffer->len, 
                              FALSE, TRUE);
@@ -148,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;
       }
@@ -167,15 +166,17 @@ void silc_server_notify(SilcServer server,
        entry for the client. */
     client = silc_idlist_find_client_by_id(server->global_list, 
                                           client_id, server->server_type, 
-                                          NULL);
+                                          &cache);
     if (!client) {
       client = silc_idlist_find_client_by_id(server->local_list, 
                                             client_id, server->server_type,
-                                            NULL);
+                                            &cache);
       if (!client) {
        /* If router did not find the client the it is bogus */
-       if (server->server_type != SILC_SERVER)
+       if (server->server_type != SILC_SERVER) {
+         silc_free(client_id);
          goto out;
+       }
 
        client = 
          silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
@@ -190,6 +191,7 @@ void silc_server_notify(SilcServer server,
        client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
       }
     }
+    silc_free(client_id);
 
     /* Do not process the notify if the client is not registered */
     if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
@@ -197,7 +199,8 @@ void silc_server_notify(SilcServer server,
 
     /* Do not add client to channel if it is there already */
     if (silc_server_client_on_channel(client, channel, NULL)) {
-      SILC_LOG_DEBUG(("Client already on channel"));
+      SILC_LOG_DEBUG(("Client already on channel %s",
+                     channel->channel_name));
       break;
     }
 
@@ -219,17 +222,27 @@ 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);
-    silc_free(client_id);
     channel->user_count++;
     channel->disabled = FALSE;
 
+    /* Make sure we don't expire clients that are on channel */
+    if (cache)
+      cache->expire = 0;
+
     /* Update statistics */
     if (server->server_type == SILC_ROUTER) {
       if (sock->type != SILC_SOCKET_TYPE_ROUTER)
@@ -259,6 +272,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;
       }
@@ -409,13 +423,17 @@ 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;
       }
     }
+    silc_free(channel_id);
 
-    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;
+    }
 
     if (client) {
       /* Get user's channel entry and check that topic set is allowed. */
@@ -434,10 +452,9 @@ 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);
     break;
 
   case SILC_NOTIFY_TYPE_NICK_CHANGE:
@@ -464,8 +481,10 @@ void silc_server_notify(SilcServer server,
       if (!id2)
        goto out;
       client_id2 = silc_id_payload_parse_id(id2, tmp_len, NULL);
-      if (!client_id2)
+      if (!client_id2) {
+       silc_free(client_id);
        goto out;
+      }
       
       SILC_LOG_DEBUG(("Old Client ID id(%s)", 
                      silc_id_render(client_id, SILC_ID_CLIENT)));
@@ -504,9 +523,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)
@@ -544,6 +563,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;
       }
@@ -559,6 +579,38 @@ void silc_server_notify(SilcServer server,
     /* Check if mode changed */
     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 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;
     }
 
@@ -568,22 +620,51 @@ 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,
+                                     SILC_ID_SERVER, channel->cipher,
                                      channel->hmac_name,
                                      channel->passphrase,
                                      channel->founder_key);
        goto out;
       }
+
+      /* 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
@@ -694,9 +775,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)
@@ -734,6 +815,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;
        }
@@ -797,10 +879,15 @@ void silc_server_notify(SilcServer server,
       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 &&
-         sock->user_data != server->router) {
+         sock != SILC_PRIMARY_ROUTE(server)) {
        SilcPublicKey founder_key = NULL;
 
        /* If channel doesn't have founder auth mode then it's impossible
@@ -809,7 +896,7 @@ void silc_server_notify(SilcServer server,
           founder at all on the channel. */
        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;
@@ -829,7 +916,7 @@ void silc_server_notify(SilcServer server,
                 silc_pkcs_public_key_compare(
                                        channel->founder_key,
                                        chl2->client->data.public_key))) {
-             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;
@@ -844,30 +931,30 @@ 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;
+           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)) {
-           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;
@@ -890,21 +977,23 @@ void silc_server_notify(SilcServer server,
          silc_pkcs_public_key_free(founder_key);
       }
 
-      if (chl->mode == mode) {
+      if (server->server_type != SILC_SERVER && chl->mode == mode) {
        SILC_LOG_DEBUG(("Mode is changed already"));
        break;
       }
 
-      SILC_LOG_DEBUG(("Changing the channel user mode"));
+      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, NULL, channel, 
-                                          packet->type, 
-                                          FALSE, packet->buffer->data, 
+       silc_server_packet_send_to_channel(server, NULL, channel,
+                                          packet->type,
+                                          FALSE, packet->buffer->data,
                                           packet->buffer->len, FALSE);
       
       silc_free(channel_id);
@@ -933,6 +1022,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;
       }
@@ -1040,6 +1130,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;
       }
@@ -1085,6 +1176,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,
@@ -1093,13 +1191,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,
@@ -1142,7 +1233,7 @@ void silc_server_notify(SilcServer server,
     /* Get server entry */
     server_entry = silc_idlist_find_server_by_id(server->global_list, 
                                                 server_id, TRUE, NULL);
-    local = TRUE;
+    local = FALSE;
     if (!server_entry) {
       server_entry = silc_idlist_find_server_by_id(server->local_list, 
                                                   server_id, TRUE, NULL);
@@ -1201,6 +1292,7 @@ void silc_server_notify(SilcServer server,
              silc_server_del_from_watcher_list(server, client);
 
            /* Remove the client */
+           silc_idlist_del_data(client);
            silc_idlist_del_client(local ? server->local_list :
                                   server->global_list, client);
          }
@@ -1212,9 +1304,19 @@ void silc_server_notify(SilcServer server,
     }
     silc_free(server_id);
 
-    /* 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);
+    /* Sending SERVER_SIGNOFF is not right way to signoff local connection */
+    if (SILC_IS_LOCAL(server_entry))
+      break;
+
+    /* Remove all servers that are originated from this server, and
+       remove the clients of those servers too. */
+    silc_server_remove_servers_by_server(server, server_entry, TRUE);
+
+    /* Remove the clients that this server owns as they will become
+       invalid now too. */
+    silc_server_remove_clients_by_server(server, server_entry->router,
+                                        server_entry, TRUE);
+    silc_server_backup_del(server, server_entry);
 
     /* Remove the server entry */
     silc_idlist_del_server(local ? server->local_list :
@@ -1247,6 +1349,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;
       }
@@ -1340,10 +1443,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;
@@ -1387,7 +1490,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;
          }
@@ -1406,10 +1510,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;
     }
 
@@ -1447,12 +1566,6 @@ 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;
@@ -1474,6 +1587,8 @@ void silc_server_notify(SilcServer server,
          server->stat.detached--;
       }
     }
+    SILC_UMODE_STATS_UPDATE(server, SILC_UMODE_SERVER_OPERATOR);
+    SILC_UMODE_STATS_UPDATE(router, SILC_UMODE_ROUTER_OPERATOR);
 
     /* Change the mode */
     client->mode = mode;
@@ -1507,6 +1622,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;
       }
@@ -1579,6 +1695,7 @@ void silc_server_notify(SilcServer server,
          if (client) {
            silc_server_remove_from_channels(server, NULL, client, TRUE, 
                                             NULL, TRUE);
+           silc_idlist_del_data(client);
            silc_idlist_del_client(server->global_list, client);
          }
          silc_free(client_id);
@@ -1986,7 +2103,7 @@ void silc_server_channel_key(SilcServer server,
   
   if (server->server_type != SILC_BACKUP_ROUTER) {
     /* Distribute to local cell backup routers. */
-    silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
+    silc_server_backup_send(server, sock->user_data, 
                            SILC_PACKET_CHANNEL_KEY, 0,
                            buffer->data, buffer->len, FALSE, TRUE);
   }
@@ -2173,6 +2290,25 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     snprintf(&nickname[strlen(nickname) - 1], 1, "%d", nickfail);
   }
 
+  /* If client marked as anonymous, scramble the username and hostname */
+  if (client->mode & SILC_UMODE_ANONYMOUS) {
+    char *scramble;
+
+    if (strlen(username) >= 2) {
+      username[0] = silc_rng_get_byte_fast(server->rng);
+      username[1] = silc_rng_get_byte_fast(server->rng);
+    }
+
+    scramble = silc_hash_babbleprint(server->sha1hash, username,
+                                    strlen(username));
+    scramble[5] = '@';
+    scramble[11] = '.';
+    memcpy(&scramble[16], ".silc", 5);
+    scramble[21] = '\0';
+    silc_free(username);
+    username = scramble;
+  }
+
   /* Update client entry */
   idata->status |= SILC_IDLIST_STATUS_REGISTERED;
   client->nickname = nickname;
@@ -2193,7 +2329,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   /* 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,
+    silc_server_backup_send(server, sock->user_data, SILC_PACKET_NEW_ID, 0,
                            idp->data, idp->len, FALSE, TRUE);
     silc_buffer_free(idp);
   }
@@ -2353,7 +2489,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   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,
+    silc_server_backup_send(server, sock->user_data, SILC_PACKET_NEW_ID, 0,
                            idp->data, idp->len, FALSE, TRUE);
     silc_buffer_free(idp);
 
@@ -2391,6 +2527,36 @@ SilcServerEntry silc_server_new_server(SilcServer server,
       silc_server_announce_clients(server, 0, sock);
       silc_server_announce_channels(server, 0, sock);
     }
+
+    /* Announce our information to backup router */
+    if (new_server->server_type == SILC_BACKUP_ROUTER &&
+       sock->type == SILC_SOCKET_TYPE_SERVER &&
+       server->server_type == SILC_ROUTER) {
+      silc_server_announce_servers(server, TRUE, 0, sock);
+      silc_server_announce_clients(server, 0, sock);
+      silc_server_announce_channels(server, 0, sock);
+    }
+
+    /* If backup router, mark it as one of ours.  This server is considered
+       to be backup router after this setting. */
+    if (new_server->server_type == SILC_BACKUP_ROUTER) {
+      SilcServerConfigRouter *backup;
+      backup = silc_server_config_find_backup_conn(server, sock->ip);
+      if (!backup)
+       backup = silc_server_config_find_backup_conn(server, sock->hostname);
+      if (backup) {
+       /* Add as our backup router */
+       silc_server_backup_add(server, new_server, backup->backup_replace_ip,
+                              backup->backup_replace_port,
+                              backup->backup_local);
+      }
+    }
+
+    /* 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;
@@ -2586,7 +2752,7 @@ static void silc_server_new_id_real(SilcServer server,
                            packet->type, 
                            packet->flags | SILC_PACKET_FLAG_BROADCAST,
                            buffer->data, buffer->len, FALSE);
-    silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
+    silc_server_backup_send(server, sock->user_data, 
                            packet->type, packet->flags,
                            packet->buffer->data, packet->buffer->len, 
                            FALSE, TRUE);
@@ -2634,7 +2800,7 @@ void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
                            packet->flags | SILC_PACKET_FLAG_BROADCAST,
                            packet->buffer->data, 
                            packet->buffer->len, FALSE);
-    silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
+    silc_server_backup_send(server, sock->user_data, 
                            packet->type, packet->flags,
                            packet->buffer->data, packet->buffer->len, 
                            FALSE, TRUE);
@@ -2644,7 +2810,7 @@ void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
      data buffer, which we will here now fetch from the original buffer. */
   new_id = silc_packet_context_alloc();
   new_id->type = SILC_PACKET_NEW_ID;
-  new_id->flags = packet->flags;
+  new_id->flags = packet->flags & (~SILC_PACKET_FLAG_LIST);
   new_id->src_id = packet->src_id;
   new_id->src_id_len = packet->src_id_len;
   new_id->src_id_type = packet->src_id_type;
@@ -2693,8 +2859,6 @@ void silc_server_new_channel(SilcServer server,
   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)
@@ -2741,7 +2905,7 @@ void silc_server_new_channel(SilcServer server,
                                0, channel_id, sock->user_data, NULL, NULL, 0);
       if (!channel)
        return;
-      channel->disabled = TRUE;
+      channel->disabled = TRUE;    /* Disabled until someone JOINs */
 
       server->stat.channels++;
       if (server->server_type == SILC_ROUTER)
@@ -2766,6 +2930,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
@@ -2774,13 +2940,15 @@ void silc_server_new_channel(SilcServer server,
          !SILC_ID_COMPARE(channel_id, server->id, server->id->ip.data_len)) {
        SilcChannelID *tmp;
        SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
-       
        if (silc_id_create_channel_id(server, server->id, server->rng, &tmp)) {
          silc_server_send_notify_channel_change(server, sock, FALSE, 
                                                 channel_id, tmp);
          silc_free(channel_id);
-         channel_id = tmp;
+         silc_free(tmp);
        }
+
+       /* Wait that server re-announces this channel */
+       return;
       }
 
       /* Create the channel with the provided Channel ID */
@@ -2792,7 +2960,16 @@ void silc_server_new_channel(SilcServer server,
        silc_free(channel_id);
        return;
       }
-      channel->disabled = TRUE;
+      channel->disabled = TRUE;    /* Disabled until someone JOINs */
+
+#if 0 /* We assume that CMODE_CHANGE notify is sent to us after this. */
+
+      /* XXX Dunno if this is supposed to be set in any server type.  If set
+        here the CMODE_CHANGE that may follow sets mode that we already
+        have, and we may loose data from the CMODE_CHANGE notify. */
+      if (server_entry->server_type != SILC_BACKUP_ROUTER)
+       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);
@@ -2812,6 +2989,8 @@ void silc_server_new_channel(SilcServer server,
         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. */
@@ -2823,8 +3002,8 @@ void silc_server_new_channel(SilcServer server,
        return;
       }
 
-#if 0 /* Lets expect that server send CMODE_CHANGE notify anyway to
-        (attempt) force mode change, and may very well get it. */
+#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. */
@@ -2843,15 +3022,18 @@ void silc_server_new_channel(SilcServer server,
       /* Create new key for the channel and send it to the server and
         everybody else possibly on the channel. */
       if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
-       if (!silc_server_create_channel_key(server, channel, 0))
-         return;
-       
-       /* Send to the channel */
-       silc_server_send_channel_key(server, sock, channel, FALSE);
-       id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-       id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
+
+       if (silc_hash_table_count(channel->user_list)) {
+         if (!silc_server_create_channel_key(server, channel, 0))
+           return;
+
+         /* Send to the channel */
+         silc_server_send_channel_key(server, sock, channel, FALSE);
+       }
 
        /* Send to the server */
+       id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+       id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
        chk = silc_channel_key_payload_encode(id_len, id,
                                              strlen(channel->channel_key->
                                                     cipher->name),
@@ -2876,6 +3058,13 @@ void silc_server_new_channel(SilcServer server,
         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,
@@ -2884,13 +3073,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,
@@ -2910,6 +3092,24 @@ void silc_server_new_channel(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->server_type == SILC_ROUTER &&
+      sock->type == SILC_SOCKET_TYPE_SERVER &&
+      !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+    SILC_LOG_DEBUG(("Broadcasting received New Channel packet"));
+    silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
+                           packet->type, 
+                           packet->flags | SILC_PACKET_FLAG_BROADCAST,
+                           packet->buffer->data, 
+                           packet->buffer->len, FALSE);
+    silc_server_backup_send(server, sock->user_data, 
+                           packet->type, packet->flags,
+                           packet->buffer->data, packet->buffer->len, 
+                           FALSE, TRUE);
+  }
+
   silc_channel_payload_free(payload);
 }
 
@@ -2931,29 +3131,11 @@ void silc_server_new_channel_list(SilcServer server,
       server->server_type == SILC_SERVER)
     return;
 
-  /* 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->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, SILC_PRIMARY_ROUTE(server),
-                           packet->type, 
-                           packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           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, 
-                           FALSE, TRUE);
-  }
-
   /* Make copy of the original packet context, except for the actual
      data buffer, which we will here now fetch from the original buffer. */
   new = silc_packet_context_alloc();
   new->type = SILC_PACKET_NEW_CHANNEL;
-  new->flags = packet->flags;
+  new->flags = packet->flags & (~SILC_PACKET_FLAG_LIST);
   new->src_id = packet->src_id;
   new->src_id_len = packet->src_id_len;
   new->src_id_type = packet->src_id_type;
@@ -3226,6 +3408,7 @@ void silc_server_resume_client(SilcServer server,
 {
   SilcBuffer buffer = packet->buffer, buf;
   SilcIDListData idata;
+  SilcIDCacheEntry id_cache = NULL;
   SilcClientEntry detached_client;
   SilcClientID *client_id = NULL;
   unsigned char *id_string, *auth = NULL;
@@ -3460,8 +3643,10 @@ void silc_server_resume_client(SilcServer server,
     server->stat.clients--;
     if (server->stat.cell_clients)
       server->stat.cell_clients--;
+    silc_server_remove_from_channels(server, NULL, client, FALSE, NULL, FALSE);
     silc_server_del_from_watcher_list(server, client);
-    silc_idlist_del_client(server->local_list, client);
+    if (!silc_idlist_del_client(server->local_list, client))
+      silc_idlist_del_client(server->global_list, client);
     client = detached_client;
 
     /* If the ID is not based in our ID then change it */
@@ -3595,10 +3780,12 @@ void silc_server_resume_client(SilcServer server,
 
     /* 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, 
-                                                   client_id, TRUE, NULL);
+                                                   client_id, TRUE,
+                                                   &id_cache);
     if (!detached_client) {
       detached_client = silc_idlist_find_client_by_id(server->global_list,
-                                                     client_id, TRUE, NULL);
+                                                     client_id, TRUE,
+                                                     &id_cache);
       if (!detached_client) {
        SILC_LOG_DEBUG(("Resuming client is unknown"));
        silc_free(client_id);
@@ -3628,10 +3815,41 @@ void silc_server_resume_client(SilcServer server,
       return;
     }
 
+    SILC_LOG_DEBUG(("Resuming detached client"));
+
+    /* 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->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, SILC_PRIMARY_ROUTE(server),
+                             packet->type, 
+                             packet->flags | SILC_PACKET_FLAG_BROADCAST,
+                             buffer->data, buffer->len, FALSE);
+      silc_server_backup_send(server, sock->user_data, 
+                             packet->type, packet->flags,
+                             packet->buffer->data, packet->buffer->len, 
+                             FALSE, TRUE);
+    }
+
     /* Client is detached, and now it is resumed.  Remove the detached
        mode and mark that it is resumed. */
     detached_client->mode &= ~SILC_UMODE_DETACHED;
     detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED;
+    detached_client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
+    id_cache->expire = 0;
+
+    /* Update channel information regarding global clients on channel. */
+    if (server->server_type == SILC_SERVER) {
+      silc_hash_table_list(detached_client->channels, &htl);
+      while (silc_hash_table_get(&htl, NULL, (void **)&chl))
+       chl->channel->global_users = 
+         silc_server_channel_has_global(chl->channel);
+      silc_hash_table_list_reset(&htl);
+    }
+
+    silc_schedule_task_del_by_context(server->schedule, detached_client);
 
     /* Get the new owner of the resumed client */
     server_id = silc_id_str2id(packet->src_id, packet->src_id_len,
@@ -3661,8 +3879,6 @@ void silc_server_resume_client(SilcServer server,
        server_entry->server_type == SILC_ROUTER)
       local = FALSE;
 
-    SILC_LOG_DEBUG(("Resuming detached client"));
-
     /* Change the client to correct list. */
     if (!silc_idcache_del_by_context(server->local_list->clients,
                                     detached_client))
@@ -3674,36 +3890,8 @@ void silc_server_resume_client(SilcServer server,
                     detached_client->nickname,
                     detached_client->id, detached_client, FALSE, NULL);
 
-    /* Change the owner of the client if needed */
-    if (detached_client->router != server_entry)
-      detached_client->router = server_entry;
-
-    /* Update channel information regarding global clients on channel. */
-    if (server->server_type == SILC_SERVER) {
-      silc_hash_table_list(detached_client->channels, &htl);
-      while (silc_hash_table_get(&htl, NULL, (void **)&chl))
-       chl->channel->global_users = 
-         silc_server_channel_has_global(chl->channel);
-      silc_hash_table_list_reset(&htl);
-    }
-
-    silc_schedule_task_del_by_context(server->schedule, detached_client);
-
-    /* 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->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, SILC_PRIMARY_ROUTE(server),
-                             packet->type, 
-                             packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                             buffer->data, buffer->len, FALSE);
-      silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
-                             packet->type, packet->flags,
-                             packet->buffer->data, packet->buffer->len, 
-                             FALSE, TRUE);
-    }
+    /* Change the owner of the client */
+    detached_client->router = server_entry;
 
     silc_free(server_id);
   }