Fixed topic annoucning, server signoff handling, added -D option,
[silc.git] / apps / silcd / packet_receive.c
index 03fcde91e8430f7cb9e16d2072bb163e618e7920..ac06a7d2e4c6c0f0c5d4eb74c503febc4d1c0509 100644 (file)
@@ -86,7 +86,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 +97,13 @@ 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, 
-                                  channel_id, SILC_ID_CHANNEL,
-                                  packet->buffer->data, packet->buffer->len, 
-                                  FALSE);
+      if (!server->standalone)
+       silc_server_packet_send_dest(server, server->router->connection, 
+                                    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, 
                                   packet->type, packet->flags,
                                   channel_id, SILC_ID_CHANNEL,
@@ -110,11 +111,12 @@ void silc_server_notify(SilcServer server,
                                   FALSE, TRUE);
     } else {
       /* Packet is destined to client or server */
-      silc_server_packet_send(server, server->router->connection, 
-                             packet->type,
-                             packet->flags | SILC_PACKET_FLAG_BROADCAST, 
-                             packet->buffer->data, packet->buffer->len, 
-                             FALSE);
+      if (!server->standalone)
+       silc_server_packet_send(server, server->router->connection, 
+                               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, 
@@ -229,6 +231,14 @@ void silc_server_notify(SilcServer server,
     silc_hash_table_add(client->channels, channel, chl);
     silc_free(client_id);
     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;
 
@@ -358,22 +368,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);
@@ -404,14 +416,16 @@ void silc_server_notify(SilcServer server,
     if (channel->topic && !strcmp(channel->topic, tmp))
       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 */
@@ -553,6 +567,20 @@ void silc_server_notify(SilcServer server,
        SILC_LOG_DEBUG(("CMODE change is not allowed"));
        goto out;
       }
+    } else {
+      if (server->server_type == SILC_ROUTER &&
+         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 */
@@ -628,12 +656,23 @@ void silc_server_notify(SilcServer server,
        if (channel->founder_key)
          silc_pkcs_public_key_free(channel->founder_key);
        channel->founder_key = NULL;
-      } else if (!client->data.public_key) {
+      } else if (client && !client->data.public_key) {
        client->data.public_key = 
          silc_pkcs_public_key_copy(channel->founder_key);
       }
     }
 
+    if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH && !channel->founder_key &&
+       server->server_type == SILC_ROUTER) {
+      SILC_LOG_DEBUG(("Enforcing sender to change channel mode"));
+      mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
+      silc_server_send_notify_cmode(server, sock, FALSE, channel,
+                                   mode, server->id, SILC_ID_SERVER,
+                                   channel->cipher, 
+                                   channel->hmac_name,
+                                   channel->passphrase, NULL);
+    }
+
     /* Change mode */
     channel->mode = mode;
 
@@ -732,7 +771,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)) {
@@ -740,7 +779,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;
 
@@ -752,17 +790,21 @@ void silc_server_notify(SilcServer server,
        }
       }
 
+      /* Get target channel user entry */
+      if (!silc_server_client_on_channel(client2, channel, &chl))
+       goto out;
+
       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->user_data != server->router) {
+       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;
          silc_server_force_cumode_change(server, sock, channel, chl, mode);
@@ -776,7 +818,8 @@ void silc_server_notify(SilcServer server,
        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);
+           silc_server_force_cumode_change(server, sock, channel,
+                                           chl, mode);
            notify_sent = TRUE;
            break;
          }
@@ -784,14 +827,59 @@ void silc_server_notify(SilcServer server,
        if (!(mode & SILC_CHANNEL_UMODE_CHANFO))
          break;
 
-       /* XXX Founder not found of the channel.  Since the founder auth mode
+       /* Founder not found of the channel.  Since the founder auth mode
           is set on the channel now check whether this is the client that
-          originally set the mode. If we don't have the public key it
-          is resolved first.
-       if (!silc_pkcs_public_key_compare(channel->founder_key,
-                                         client->data.public_key))
-       */
+          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) {
+         /* 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;
+         }
+       }
+
+       /* 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);
+      }
+
+      if (server->server_type == SILC_ROUTER && chl->mode == mode) {
+       SILC_LOG_DEBUG(("Mode is changed already"));
+       break;
       }
 
       SILC_LOG_DEBUG(("Changing the channel user mode"));
@@ -972,7 +1060,7 @@ void silc_server_notify(SilcServer server,
       }
 
     if (channel_id2) {
-      SilcBuffer users = NULL, users_modes = NULL;
+      SilcBuffer modes = NULL, users = NULL, users_modes = NULL;
 
       /* Re-announce this channel which ID was changed. */
       silc_server_send_new_channel(server, sock, FALSE, channel->channel_name,
@@ -982,8 +1070,16 @@ void silc_server_notify(SilcServer server,
                                   channel->mode);
 
       /* Re-announce our clients on the channel as the ID has changed now */
-      silc_server_announce_get_channel_users(server, channel, &users,
+      silc_server_announce_get_channel_users(server, channel, &modes, &users,
                                             &users_modes);
+      if (modes) {
+       silc_buffer_push(modes, modes->data - modes->head);
+       silc_server_packet_send_dest(server, sock,
+                                    SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                                    channel->id, SILC_ID_CHANNEL,
+                                    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,
@@ -1006,7 +1102,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);
       }
     }
@@ -1111,7 +1207,9 @@ void silc_server_notify(SilcServer server,
     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;
 
@@ -1346,6 +1444,24 @@ void silc_server_notify(SilcServer server,
     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;
 
@@ -1803,6 +1919,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 
@@ -1891,6 +2011,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     SILC_LOG_INFO(("Unauthenticated client attempted to register to network"));
     silc_server_disconnect_remote(server, sock, 
                                  SILC_STATUS_ERR_NOT_AUTHENTICATED, NULL);
+    if (sock->user_data)
+      silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
@@ -1908,6 +2030,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     silc_server_disconnect_remote(server, sock, 
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION, 
                                  NULL);
+    if (sock->user_data)
+      silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
@@ -1919,6 +2043,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     silc_server_disconnect_remote(server, sock, 
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
+    if (sock->user_data)
+      silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
@@ -1955,6 +2081,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
       silc_server_disconnect_remote(server, sock, 
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    NULL);
+      if (sock->user_data)
+       silc_server_free_sock_user_data(server, sock, NULL);
       return NULL;
     }
     
@@ -1975,6 +2103,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
       silc_server_disconnect_remote(server, sock, 
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    NULL);
+      if (sock->user_data)
+       silc_server_free_sock_user_data(server, sock, NULL);
       return NULL;
     }
     
@@ -2023,6 +2153,8 @@ SilcClientEntry silc_server_new_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 NULL;
     }
     snprintf(&nickname[strlen(nickname) - 1], 1, "%d", nickfail);
@@ -2046,7 +2178,15 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                            server->router->connection, 
                            server->server_type == SILC_ROUTER ? TRUE : FALSE,
                            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));
@@ -2101,6 +2241,8 @@ SilcServerEntry silc_server_new_server(SilcServer server,
                                 "server" : "router")));
       silc_server_disconnect_remote(server, sock, 
                                    SILC_STATUS_ERR_NOT_AUTHENTICATED, NULL);
+      if (sock->user_data)
+       silc_server_free_sock_user_data(server, sock, NULL);
       return NULL;
     }
     local = FALSE;
@@ -2113,16 +2255,24 @@ SilcServerEntry silc_server_new_server(SilcServer server,
                                                         &name_len),
                             SILC_STR_END);
   if (ret == -1) {
-    if (id_string)
-      silc_free(id_string);
-    if (server_name)
-      silc_free(server_name);
+    silc_free(id_string);
+    silc_free(server_name);
+    silc_server_disconnect_remote(server, sock, 
+                                 SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                 NULL);
+    if (sock->user_data)
+      silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
   if (id_len > buffer->len) {
     silc_free(id_string);
     silc_free(server_name);
+    silc_server_disconnect_remote(server, sock, 
+                                 SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                 NULL);
+    if (sock->user_data)
+      silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
 
@@ -2134,6 +2284,11 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   if (!server_id) {
     silc_free(id_string);
     silc_free(server_name);
+    silc_server_disconnect_remote(server, sock, 
+                                 SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                 NULL);
+    if (sock->user_data)
+      silc_server_free_sock_user_data(server, sock, NULL);
     return NULL;
   }
   silc_free(id_string);
@@ -2144,6 +2299,8 @@ SilcServerEntry silc_server_new_server(SilcServer server,
                   sock->ip, sock->hostname));
     silc_server_disconnect_remote(server, sock, 
                                  SILC_STATUS_ERR_BAD_SERVER_ID, NULL);
+    if (sock->user_data)
+      silc_server_free_sock_user_data(server, sock, NULL);
     silc_free(server_name);
     return NULL;
   }
@@ -2182,8 +2339,16 @@ SilcServerEntry silc_server_new_server(SilcServer 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
@@ -2402,14 +2567,15 @@ 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,
-                           packet->type, 
-                           packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           buffer->data, buffer->len, FALSE);
+    if (!server->standalone)
+      silc_server_packet_send(server, server->router->connection,
+                             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, 
@@ -2449,14 +2615,16 @@ 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,
-                           packet->type, 
-                           packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           packet->buffer->data, packet->buffer->len, FALSE);
+    if (!server->standalone)
+      silc_server_packet_send(server, server->router->connection,
+                             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, 
@@ -2565,6 +2733,7 @@ void silc_server_new_channel(SilcServer server,
                                0, channel_id, sock->user_data, NULL, NULL, 0);
       if (!channel)
        return;
+      channel->disabled = TRUE;
 
       server->stat.channels++;
       if (server->server_type == SILC_ROUTER)
@@ -2615,9 +2784,7 @@ void silc_server_new_channel(SilcServer server,
        silc_free(channel_id);
        return;
       }
-
-      /* Get the mode and set it to the channel */
-      channel->mode = silc_channel_get_mode(payload);
+      channel->disabled = TRUE;
 
       /* Send the new channel key to the server */
       id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
@@ -2631,12 +2798,11 @@ 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 users = NULL, users_modes = NULL;
+      SilcBuffer modes = NULL, users = NULL, users_modes = NULL;
 
       if (!SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
        /* They don't match, send CHANNEL_CHANGE notify to the server to
@@ -2644,8 +2810,14 @@ void silc_server_new_channel(SilcServer server,
        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 /* Lets expect that server send CMODE_CHANGE notify anyway to
+        (attempt) force mode change, and may very well get it. */
+
       /* If the mode is different from what we have then enforce the
         mode change. */
       mode = silc_channel_get_mode(payload);
@@ -2658,6 +2830,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. */
@@ -2686,11 +2859,23 @@ 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, &users,
+      silc_server_announce_get_channel_users(server, channel, &modes, &users,
                                             &users_modes);
+      if (modes) {
+       silc_buffer_push(modes, modes->data - modes->head);
+       silc_server_packet_send_dest(server, sock,
+                                    SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                                    channel->id, SILC_ID_CHANNEL,
+                                    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,
@@ -2707,6 +2892,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);
+      }
     }
   }
 
@@ -2734,14 +2926,16 @@ 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,
-                           packet->type, 
-                           packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           packet->buffer->data, packet->buffer->len, FALSE);
+    if (!server->standalone)
+      silc_server_packet_send(server, server->router->connection,
+                             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, 
@@ -3169,7 +3363,8 @@ void silc_server_resume_client(SilcServer server,
 
     /* Verify the authentication payload.  This has to be successful in
        order to allow the resuming */
-    if (!silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
+    if (!idata->hash ||
+       !silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
                               detached_client->data.public_key, 0,
                               idata->hash, detached_client->id, 
                               SILC_ID_CLIENT)) {
@@ -3193,6 +3388,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. */
@@ -3224,6 +3420,7 @@ 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;
 
@@ -3439,14 +3636,15 @@ 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,
-                             packet->type, 
-                             packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                             buffer->data, buffer->len, FALSE);
+      if (!server->standalone)
+       silc_server_packet_send(server, server->router->connection,
+                               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,