Fixed founder mode chaning in JOIN and CUMODE_CHANGE notifys.
[silc.git] / apps / silcd / command.c
index 9efae7374e4762f7f92ed47a60ba814c1a7d63af..50d620a2adda7e60277baea9e5072cd618499543 100644 (file)
@@ -187,6 +187,8 @@ void silc_server_command_process(SilcServer server,
   SilcServerCommand *cmd;
   SilcCommand command;
 
+  SILC_LOG_DEBUG(("Start"));
+
   /* Allocate command context. This must be free'd by the
      command routine receiving it. */
   ctx = silc_server_command_alloc();
@@ -199,7 +201,6 @@ void silc_server_command_process(SilcServer server,
                                            packet->buffer->len);
   if (!ctx->payload) {
     SILC_LOG_ERROR(("Bad command payload, packet dropped"));
-    silc_buffer_free(packet->buffer);
     silc_packet_context_free(packet);
     silc_socket_free(ctx->sock);
     silc_free(ctx);
@@ -477,16 +478,18 @@ silc_server_command_pending_error_check(SilcServerCommandContext cmd,
 
 typedef struct {
   void *id;
+  SilcIdType id_type;
   SilcUInt32 index;
   SilcStatus error;
 } *ResolveError;
 
-#define ADD_ERROR(errptr, errptr_count, _id, _index, _status)          \
+#define ADD_ERROR(errptr, errptr_count, _id, _id_type, _index, _status)        \
 do {                                                                   \
   errptr = silc_realloc(errptr, sizeof(*errptr) * (errptr_count + 1)); \
   if (!errptr)                                                         \
     return FALSE;                                                      \
   errptr[errptr_count].id = _id;                                       \
+  errptr[errptr_count].id_type = _id_type;                             \
   errptr[errptr_count].index = _index;                                 \
   errptr[errptr_count].error = _status;                                        \
   errptr_count++;                                                      \
@@ -509,7 +512,7 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd,
   int i, k;
 
   /* If client ID is in the command it must be used instead of nickname */
-  tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+  tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
   if (!tmp) {
     /* No ID, get the nickname@server string and parse it. */
     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
@@ -524,7 +527,7 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd,
     /* Command includes ID, we must use that.  Take all ID's from the 
        command packet */
     for (k = 0, i = 0; i < argc; i++) {
-      tmp = silc_argument_get_arg_type(cmd->args, i + 3, &len);
+      tmp = silc_argument_get_arg_type(cmd->args, i + 4, &len);
       if (!tmp)
        continue;
       id = silc_id_payload_parse_id(tmp, len, NULL);
@@ -535,7 +538,7 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd,
        (*client_id_count)++;
        k++;
       } else {
-       ADD_ERROR((*error_client), (*error_client_count), NULL, i + 3,
+       ADD_ERROR((*error_client), (*error_client_count), NULL, 0, i + 4,
                  SILC_STATUS_ERR_BAD_CLIENT_ID);
       }
     }
@@ -543,11 +546,10 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd,
 
   /* Get the max count of reply messages allowed */
   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
-  if (tmp) {
+  if (tmp)
     SILC_GET32_MSB(*count, tmp);
-  } else {
+  else
     *count = 0;
-  }
 
   return TRUE;
 }
@@ -653,7 +655,7 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
                                               sizeof(**r->res_argv));
        memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
        r->res_argv_lens[r->res_argc] = idp->len;
-       r->res_argv_types[r->res_argc] = r->res_argc + 3;
+       r->res_argv_types[r->res_argc] = r->res_argc + 4;
        r->res_argc++;
        silc_buffer_free(idp);
 
@@ -834,7 +836,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
       umode_list = NULL;
     }
 
-    if (count && k - 1 == count)
+    if (status == SILC_STATUS_LIST_END)
       break;
     k++;
   }
@@ -870,7 +872,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
     silc_buffer_free(idp);
     idp = NULL;
       
-    if (count && k - 1 == count)
+    if (status == SILC_STATUS_LIST_END)
       break;
     k++;
   }
@@ -963,8 +965,8 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
          goto out;
        }
 
-       ADD_ERROR(error_client, error_client_count, client_id[i], 0,
-                 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
+       ADD_ERROR(error_client, error_client_count, client_id[i], 
+                 SILC_ID_CLIENT, 0, SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
       }
     }
   } else if (nick) {
@@ -1079,11 +1081,10 @@ silc_server_command_whowas_parse(SilcServerCommandContext cmd,
 
   /* Get the max count of reply messages allowed */
   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
-  if (tmp) {
+  if (tmp)
     SILC_GET32_MSB(*count, tmp);
-  } else {
+  else
     *count = 0;
-  }
 
   return TRUE;
 }
@@ -1160,13 +1161,10 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
 
   if (!valid_count) {
     /* No valid entries found at all, just send error */
-    unsigned char *tmp;
-    
     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
-    if (tmp)
-      silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
-                                          SILC_STATUS_ERR_NO_SUCH_NICK, 0,
-                                          3, tmp, strlen(tmp));
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS,
+                                        SILC_STATUS_ERR_NO_SUCH_NICK, 0,
+                                        3, tmp, tmp ? strlen(tmp) : 0);
     return;
   }
 
@@ -1184,8 +1182,6 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
       status = SILC_STATUS_LIST_END;
     if (count && k - 1 == count)
       status = SILC_STATUS_LIST_END;
-    if (count && k - 1 > count)
-      break;
 
     /* Send WHOWAS reply */
     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
@@ -1227,6 +1223,8 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
     silc_buffer_free(packet);
     silc_buffer_free(idp);
 
+    if (status == SILC_STATUS_LIST_END)
+      break;
     k++;
   }
 }
@@ -1382,7 +1380,9 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
                                   SilcUInt32 *servers_count,
                                   SilcChannelEntry **channels,
                                   SilcUInt32 *channels_count,
-                                  SilcUInt32 *count)
+                                  SilcUInt32 *count,
+                                  ResolveError *error_id,
+                                  SilcUInt32 *error_id_count)
 {
   SilcServer server = cmd->server;
   unsigned char *tmp;
@@ -1392,7 +1392,6 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
   bool check_global = FALSE;
   void *entry;
   int i;
-  bool error = FALSE;
 
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
     check_global = TRUE;
@@ -1513,26 +1512,19 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
        continue;
       
       idp = silc_id_payload_parse(tmp, len);
-      if (!idp) {
-       silc_free(*clients);
-       silc_free(*servers);
-       silc_free(*channels);
-       silc_server_command_send_status_reply(
-                                      cmd, SILC_COMMAND_IDENTIFY,
-                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
-       return 0;
-      }
+      if (!idp)
+       ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
+                 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
 
       id = silc_id_payload_get_id(idp);
-      
       switch (silc_id_payload_get_type(idp)) {
        
       case SILC_ID_CLIENT:
-       entry = (void *)silc_idlist_find_client_by_id(server->local_list, 
-                                                     id, TRUE, NULL);
+       entry = silc_idlist_find_client_by_id(server->local_list, 
+                                             id, TRUE, NULL);
        if (!entry && check_global)
-         entry = (void *)silc_idlist_find_client_by_id(server->global_list, 
-                                                       id, TRUE, NULL);
+         entry = silc_idlist_find_client_by_id(server->global_list, 
+                                               id, TRUE, NULL);
        if (entry) {
          *clients = silc_realloc(*clients, sizeof(**clients) * 
                                  (*clients_count + 1));
@@ -1547,24 +1539,22 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
            silc_free(*clients);
            silc_free(*servers);
            silc_free(*channels);
+           silc_free(*error_id);
            return -1;
-         } else {
-           silc_server_command_send_status_data(
-                                       cmd, SILC_COMMAND_IDENTIFY,
-                                       SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                       0, 2, tmp, len);
-           error = TRUE;
          }
+
+         ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
+                   SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
        }
 
        break;
        
       case SILC_ID_SERVER:
-       entry = (void *)silc_idlist_find_server_by_id(server->local_list, 
-                                                     id, TRUE, NULL);
+       entry = silc_idlist_find_server_by_id(server->local_list, 
+                                             id, TRUE, NULL);
        if (!entry && check_global)
-         entry = (void *)silc_idlist_find_server_by_id(server->global_list, 
-                                                       id, TRUE, NULL);
+         entry = silc_idlist_find_server_by_id(server->global_list, 
+                                               id, TRUE, NULL);
        if (entry) {
          *servers = silc_realloc(*servers, sizeof(**servers) * 
                                  (*servers_count + 1));
@@ -1579,23 +1569,20 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
            silc_free(*clients);
            silc_free(*servers);
            silc_free(*channels);
+           silc_free(*error_id);
            return -1;
-         } else {
-           silc_server_command_send_status_data(
-                                        cmd, SILC_COMMAND_IDENTIFY,
-                                        SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
-                                        0, 2, tmp, len);
-           error = TRUE;
          }
+
+         ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
+                   SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
        }
        break;
        
       case SILC_ID_CHANNEL:
-       entry = (void *)silc_idlist_find_channel_by_id(server->local_list, 
-                                                      id, NULL);
+       entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
        if (!entry && check_global)
-         entry = (void *)silc_idlist_find_channel_by_id(server->global_list, 
-                                                        id, NULL);
+         entry = silc_idlist_find_channel_by_id(server->global_list, id,
+                                                NULL);
        if (entry) {
          *channels = silc_realloc(*channels, sizeof(**channels) * 
                                   (*channels_count + 1));
@@ -1610,14 +1597,12 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
            silc_free(*clients);
            silc_free(*servers);
            silc_free(*channels);
+           silc_free(*error_id);
            return -1;
-         } else {
-           silc_server_command_send_status_data(
-                                        cmd, SILC_COMMAND_IDENTIFY,
-                                        SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
-                                        0, 2, tmp, len);
-           error = TRUE;
          }
+
+         ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5,
+                   SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
        }
        break;
       }
@@ -1626,20 +1611,12 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
     }
   }
 
-  if (error) {
-    silc_free(*clients);
-    silc_free(*servers);
-    silc_free(*channels);
-    return FALSE;
-  }
-  
   /* Get the max count of reply messages allowed */
   tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
-  if (tmp) {
+  if (tmp)
     SILC_GET32_MSB(*count, tmp);
-  } else {
+  else
     *count = 0;
-  }
 
   return 1;
 }
@@ -1737,7 +1714,7 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd,
                                               sizeof(**r->res_argv));
        memcpy(r->res_argv[r->res_argc], idp->data, idp->len);
        r->res_argv_lens[r->res_argc] = idp->len;
-       r->res_argv_types[r->res_argc] = r->res_argc + 3;
+       r->res_argv_types[r->res_argc] = r->res_argc + 4;
        r->res_argc++;
        silc_buffer_free(idp);
 
@@ -1793,46 +1770,46 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
                                        SilcUInt32 servers_count,
                                        SilcChannelEntry *channels,
                                        SilcUInt32 channels_count,
+                                       ResolveError errors,
+                                       SilcUInt32 errors_count,
                                        int count)
 {
   SilcServer server = cmd->server;
-  int i, k, len, valid_count;
+  int i, k, valid_count;
+  SilcUInt32 len;
   SilcBuffer packet, idp;
   SilcStatus status;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   char nh[256], uh[256];
   SilcSocketConnection hsock;
+  unsigned char *tmp;
 
   status = SILC_STATUS_OK;
 
   if (clients) {
     SilcClientEntry entry;
+    valid_count = clients_count;
+
+    if (silc_argument_get_arg_type(cmd->args, 1, NULL)) {
+      /* Process only valid clients and ignore those that are not registered. 
+        This is checked with nickname only because when resolved client IDs
+        we check that they are registered earlier. */
+      valid_count = 0;
+      for (i = 0; i < clients_count; i++) {
+       if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
+         valid_count++;
+       else
+         clients[i] = NULL;
+      }
 
-    /* Process only valid entries. */
-    valid_count = 0;
-    for (i = 0; i < clients_count; i++) {
-      if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
-       valid_count++;
-      else
-       clients[i] = NULL;
-    }
-
-    if (!valid_count) {
-      /* No valid entries found at all, just send error */
-      unsigned char *tmp;
-
-      tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
-      if (tmp) {
+      if (!valid_count) {
+       /* No valid entries found at all, just send error */
+       tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
        silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
                                             SILC_STATUS_ERR_NO_SUCH_NICK, 0,
-                                            3, tmp, strlen(tmp));
-      } else {
-       tmp = silc_argument_get_arg_type(cmd->args, 5, (SilcUInt32 *)&len);
-       silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
-                                            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                            0, 2, tmp, len);
+                                            3, tmp, tmp ? strlen(tmp) : 0);
+       return;
       }
-      return;
     }
 
     /* Process all valid client entries and send command replies */
@@ -1848,7 +1825,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
       if (k >= 1)
        status = SILC_STATUS_LIST_ITEM;
       if (valid_count > 1 && k == valid_count - 1 
-         && !servers_count && !channels_count)
+         && !servers_count && !channels_count && !errors_count)
        status = SILC_STATUS_LIST_END;
       if (count && k - 1 == count)
        status = SILC_STATUS_LIST_END;
@@ -1898,9 +1875,8 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
       silc_buffer_free(packet);
       silc_buffer_free(idp);
       
-      if (count && k - 1 == count)
+      if (status == SILC_STATUS_LIST_END)
        break;
-
       k++;
     }
   }
@@ -1916,7 +1892,8 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
       
       if (k >= 1)
        status = SILC_STATUS_LIST_ITEM;
-      if (servers_count > 1 && k == servers_count - 1 && !channels_count)
+      if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
+         !errors_count)
        status = SILC_STATUS_LIST_END;
       if (count && k - 1 == count)
        status = SILC_STATUS_LIST_END;
@@ -1936,9 +1913,8 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
       silc_buffer_free(packet);
       silc_buffer_free(idp);
       
-      if (count && k - 1 == count)
+      if (status == SILC_STATUS_LIST_END)
        break;
-
       k++;
     }
   }
@@ -1954,7 +1930,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
       
       if (k >= 1)
        status = SILC_STATUS_LIST_ITEM;
-      if (channels_count > 1 && k == channels_count - 1)
+      if (channels_count > 1 && k == channels_count - 1 && !errors_count)
        status = SILC_STATUS_LIST_END;
       if (count && k - 1 == count)
        status = SILC_STATUS_LIST_END;
@@ -1974,9 +1950,46 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
       silc_buffer_free(packet);
       silc_buffer_free(idp);
       
-      if (count && k - 1 == count)
+      if (status == SILC_STATUS_LIST_END)
        break;
+      k++;
+    }
+  }
 
+  /* Send error replies */
+  if (errors) {
+    if (status == SILC_STATUS_OK && errors_count > 1)
+      status = SILC_STATUS_LIST_START;
+
+    idp = NULL;
+    for (i = 0, k = 0; i < errors_count; i++) {
+      if (errors[i].id) {
+       idp = silc_id_payload_encode(errors[i].id, SILC_ID_CLIENT);
+       tmp = idp->data;
+       len = idp->len;
+      } else {
+       tmp = silc_argument_get_arg_type(cmd->args, errors[i].index, &len);
+      }
+      
+      if (k >= 1)
+       status = SILC_STATUS_LIST_ITEM;
+      if (errors_count > 1 && k == errors_count - 1)
+       status = SILC_STATUS_LIST_END;
+      if (count && k - 1 == count)
+       status = SILC_STATUS_LIST_END;
+      
+      /* Send error */
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+                                          (status == SILC_STATUS_OK ?
+                                           errors[i].error : status),
+                                          (status == SILC_STATUS_OK ?
+                                           0 : errors[i].error),
+                                          2, tmp, len);
+      silc_buffer_free(idp);
+      idp = NULL;
+      
+      if (status == SILC_STATUS_LIST_END)
+       break;
       k++;
     }
   }
@@ -1991,21 +2004,23 @@ silc_server_command_identify_process(SilcServerCommandContext cmd)
   SilcServerEntry *servers = NULL;
   SilcChannelEntry *channels = NULL;
   SilcUInt32 clients_count = 0, servers_count = 0, channels_count = 0;
+  SilcUInt32 errors_count = 0;
+  ResolveError errors = NULL;
 
   /* Parse the IDENTIFY request */
   ret = silc_server_command_identify_parse(cmd,
                                           &clients, &clients_count,
                                           &servers, &servers_count,
                                           &channels, &channels_count,
-                                          &count);
+                                          &count, &errors, &errors_count);
   if (ret < 1)
     return ret;
   ret = 0;
 
   /* Check that all mandatory fields are present and request those data
      from the server who owns the client if necessary. */
-  if (clients && !silc_server_command_identify_check_client(cmd, clients, 
-                                                           clients_count)) {
+  if (!silc_server_command_identify_check_client(cmd, clients, 
+                                                clients_count)) {
     ret = -1;
     goto out;
   }
@@ -2015,12 +2030,14 @@ silc_server_command_identify_process(SilcServerCommandContext cmd)
                                          clients, clients_count,
                                          servers, servers_count,
                                          channels, channels_count, 
+                                         errors, errors_count,
                                          count);
 
  out:
   silc_free(clients);
   silc_free(servers);
   silc_free(channels);
+  silc_free(errors);
   return ret;
 }
 
@@ -3158,6 +3175,8 @@ static void silc_server_command_join_channel(SilcServer server,
   char check[512], check2[512];
   bool founder = FALSE;
   bool resolve;
+  unsigned char *fkey = NULL;
+  SilcUInt32 fkey_len = 0;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -3201,21 +3220,29 @@ static void silc_server_command_join_channel(SilcServer server,
    */
   if (auth && auth_len && channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
     SilcIDListData idata = (SilcIDListData)client;
+    SilcChannelClientEntry chl2;
+    SilcHashTableList htl;
 
     if (channel->founder_key && idata->public_key &&
        silc_pkcs_public_key_compare(channel->founder_key, 
                                     idata->public_key)) {
-      void *auth_data = (channel->founder_method == SILC_AUTH_PASSWORD ?
-                        (void *)channel->founder_passwd : 
-                        (void *)channel->founder_key);
-      SilcUInt32 auth_data_len = 
-       (channel->founder_method == SILC_AUTH_PASSWORD ?
-        channel->founder_passwd_len : 0);
-
       /* Check whether the client is to become founder */
-      if (silc_auth_verify_data(auth, auth_len, channel->founder_method, 
-                               auth_data, auth_data_len,
-                               idata->hash, client->id, SILC_ID_CLIENT)) {
+      if (silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
+                               channel->founder_key, 0, server->sha1hash,
+                               client->id, SILC_ID_CLIENT)) {
+
+       /* 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);
+
        umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
        founder = TRUE;
       }
@@ -3334,6 +3361,7 @@ static void silc_server_command_join_channel(SilcServer server,
   silc_hash_table_add(channel->user_list, client, chl);
   silc_hash_table_add(client->channels, channel, chl);
   channel->user_count++;
+  channel->disabled = FALSE;
 
   /* Get users on the channel */
   silc_server_get_users_on_channel(server, channel, &user_list, &mode_list,
@@ -3360,9 +3388,12 @@ static void silc_server_command_join_channel(SilcServer server,
     silc_free(tmp);
   }
 
+  if (channel->founder_key)
+    fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len);
+
   reply = 
     silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
-                                        SILC_STATUS_OK, 0, ident, 13,
+                                        SILC_STATUS_OK, 0, ident, 14,
                                         2, channel->channel_name,
                                         strlen(channel->channel_name),
                                         3, chidp->data, chidp->len,
@@ -3386,7 +3417,8 @@ static void silc_server_command_join_channel(SilcServer server,
                                         12, tmp3, 4,
                                         13, user_list->data, user_list->len,
                                         14, mode_list->data, 
-                                        mode_list->len);
+                                        mode_list->len,
+                                        15, fkey, fkey_len);
 
   /* Send command reply */
   silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
@@ -3398,11 +3430,19 @@ static void silc_server_command_join_channel(SilcServer server,
      we'll ignore it (in packet_receive.c) so we must send it here. If
      we are router then this will send it to local clients and local
      servers. */
+  SILC_LOG_DEBUG(("Send JOIN notify to channel"));
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
                                     SILC_NOTIFY_TYPE_JOIN, 2,
                                     clidp->data, clidp->len,
                                     chidp->data, chidp->len);
 
+  /* Update statistics */
+  server->stat.my_chanclients++;
+  if (server->server_type == SILC_ROUTER) {
+    server->stat.cell_chanclients++;
+    server->stat.chanclients++;
+  }
+
   if (!cmd->pending) {
     /* Send JOIN notify packet to our primary router */
     if (!server->standalone)
@@ -3414,32 +3454,35 @@ static void silc_server_command_join_channel(SilcServer server,
       /* Distribute the channel key to all backup routers. */
       silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
                              keyp->data, keyp->len, FALSE, TRUE);
-  }
 
-  /* If client became founder by providing correct founder auth data
-     notify the mode change to the channel. */
-  if (founder) {
-    SILC_PUT32_MSB(chl->mode, mode);
-    silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
-                                      SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
-                                      clidp->data, clidp->len,
-                                      mode, 4, clidp->data, clidp->len);
-      
-    /* Set CUMODE notify type to network */
-    if (!server->standalone)
-      silc_server_send_notify_cumode(server, server->router->connection,
-                                    server->server_type == SILC_ROUTER ? 
-                                    TRUE : FALSE, channel,
-                                    chl->mode, client->id, SILC_ID_CLIENT,
-                                    client->id);
+    /* If client became founder by providing correct founder auth data
+       notify the mode change to the channel. */
+    if (founder) {
+      SILC_PUT32_MSB(chl->mode, mode);
+      SILC_LOG_DEBUG(("Send CUMODE_CHANGE notify to channel"));
+      silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
+                                        SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
+                                        clidp->data, clidp->len,
+                                        mode, 4, clidp->data, clidp->len,
+                                        fkey, fkey_len);
+    }
   }
 
+  /* Set CUMODE notify type to network */
+  if (founder && !server->standalone)
+    silc_server_send_notify_cumode(server, server->router->connection,
+                                  server->server_type == SILC_ROUTER ?
+                                  TRUE : FALSE, channel,
+                                  chl->mode, client->id, SILC_ID_CLIENT,
+                                  client->id, channel->founder_key);
+
   silc_buffer_free(reply);
   silc_buffer_free(clidp);
   silc_buffer_free(chidp);
   silc_buffer_free(keyp);
   silc_buffer_free(user_list);
   silc_buffer_free(mode_list);
+  silc_free(fkey);
 
  out:
   silc_free(passphrase);
@@ -3508,9 +3551,11 @@ SILC_SERVER_CMD_FUNC(join)
 
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
     SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
+    silc_free(client_id);
     client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
 
-    if (!channel || channel->disabled) {
+    if (!channel || 
+       (channel->disabled && server->server_type != SILC_ROUTER)) {
       /* Channel not found */
 
       /* If we are standalone server we don't have a router, we just create 
@@ -3523,6 +3568,7 @@ SILC_SERVER_CMD_FUNC(join)
                                         cmd, SILC_COMMAND_JOIN,
                                         SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
                                         0);
+         silc_free(client_id);
          goto out;
        }
        
@@ -3543,8 +3589,10 @@ SILC_SERVER_CMD_FUNC(join)
          /* If this is pending command callback then we've resolved
             it and it didn't work, return since we've notified the
             client already in the command reply callback. */
-         if (cmd->pending)
+         if (cmd->pending) {
+           silc_free(client_id);
            goto out;
+         }
          
          old_ident = silc_command_get_ident(cmd->payload);
          silc_command_set_ident(cmd->payload, ++server->cmd_ident);
@@ -3564,6 +3612,7 @@ SILC_SERVER_CMD_FUNC(join)
          cmd->pending = TRUE;
           silc_command_set_ident(cmd->payload, old_ident);
          silc_buffer_free(tmpbuf);
+         silc_free(client_id);
          goto out;
        }
        
@@ -3579,6 +3628,7 @@ SILC_SERVER_CMD_FUNC(join)
            silc_server_command_send_status_reply(
                                       cmd, SILC_COMMAND_JOIN,
                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
+           silc_free(client_id);
            goto out;
          }
 
@@ -3596,8 +3646,10 @@ SILC_SERVER_CMD_FUNC(join)
         something went wrong with the joining as the channel was not found.
         We can't do anything else but ignore this. */
       if (cmd->sock->type == SILC_SOCKET_TYPE_ROUTER ||
-         server->server_type != SILC_ROUTER)
+         server->server_type != SILC_ROUTER) {
+       silc_free(client_id);
        goto out;
+      }
       
       /* We are router and the channel does not seem exist so we will check
         our global list as well for the channel. */
@@ -3611,6 +3663,7 @@ SILC_SERVER_CMD_FUNC(join)
          silc_server_command_send_status_reply(
                                       cmd, SILC_COMMAND_JOIN,
                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
+         silc_free(client_id);
          goto out;
        }
 
@@ -3633,13 +3686,14 @@ SILC_SERVER_CMD_FUNC(join)
     }
 
     if (silc_command_get(reply->payload) == SILC_COMMAND_WHOIS &&
-       !silc_hash_table_count(channel->user_list))
+       !channel->disabled && !silc_hash_table_count(channel->user_list))
       created = TRUE;
   }
 
   /* If the channel does not have global users and is also empty the client
      will be the channel founder and operator. */
-  if (!channel->global_users && !silc_hash_table_count(channel->user_list))
+  if (!channel->disabled &&
+      !channel->global_users && !silc_hash_table_count(channel->user_list))
     umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
 
   /* Join to the channel */
@@ -3683,7 +3737,8 @@ SILC_SERVER_CMD_FUNC(motd)
     if (server->config && server->config->server_info &&
        server->config->server_info->motd_file) {
       /* Send motd */
-      motd = silc_file_readfile(server->config->server_info->motd_file, &motd_len);
+      motd = silc_file_readfile(server->config->server_info->motd_file,
+                               &motd_len);
       if (!motd)
        goto out;
       
@@ -3838,6 +3893,15 @@ SILC_SERVER_CMD_FUNC(umode)
       }
     }
 
+    /* Update statistics */
+    if (mask & SILC_UMODE_GONE) {
+      if (!(client->mode & SILC_UMODE_GONE))
+       server->stat.my_aways++;
+    } else {
+      if (client->mode & SILC_UMODE_GONE)
+       server->stat.my_aways--;
+    }
+
     /* Change the mode */
     client->mode = mask;
 
@@ -3882,6 +3946,9 @@ SILC_SERVER_CMD_FUNC(cmode)
   SilcUInt32 mode_mask = 0, tmp_len, tmp_len2;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   bool set_mask = FALSE;
+  SilcPublicKey founder_key = NULL;
+  unsigned char *fkey = NULL;
+  SilcUInt32 fkey_len = 0;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 1, 7);
 
@@ -4168,46 +4235,41 @@ SILC_SERVER_CMD_FUNC(cmode)
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
       if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
        /* Set the founder authentication */
-       SilcAuthPayload auth;
-       
        tmp = silc_argument_get_arg_type(cmd->args, 7, &tmp_len);
        if (!tmp) {
-         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+         silc_server_command_send_status_reply(
+                                    cmd, SILC_COMMAND_CMODE,
                                     SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
          goto out;
        }
 
-       auth = silc_auth_payload_parse(tmp, tmp_len);
-       if (!auth) {
+       /* Verify the payload before setting the mode */
+       if (!silc_auth_verify_data(tmp, tmp_len, SILC_AUTH_PUBLIC_KEY, 
+                                  idata->public_key, 0, server->sha1hash,
+                                  client->id, SILC_ID_CLIENT)) {
          silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+                                               SILC_STATUS_ERR_AUTH_FAILED,
+                                               0);
          goto out;
        }
 
        /* Save the public key */
-       tmp = silc_pkcs_public_key_encode(idata->public_key, &tmp_len);
-       silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key);
-       silc_free(tmp);
-       
-       channel->founder_method = silc_auth_get_method(auth);
-
-       if (channel->founder_method == SILC_AUTH_PASSWORD) {
-         tmp = silc_auth_get_data(auth, &tmp_len);
-         channel->founder_passwd = silc_memdup(tmp, tmp_len);
-         channel->founder_passwd_len = tmp_len;
-       } else {
-         /* Verify the payload before setting the mode */
-         if (!silc_auth_verify(auth, channel->founder_method, 
-                               channel->founder_key, 0, idata->hash,
-                               client->id, SILC_ID_CLIENT)) {
-           silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                                 SILC_STATUS_ERR_AUTH_FAILED,
-                                                 0);
-           goto out;
-         }
-       }
+       channel->founder_key = silc_pkcs_public_key_copy(idata->public_key);
+        if (!channel->founder_key) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                               SILC_STATUS_ERR_AUTH_FAILED,
+                                               0);
+         goto out;
+        }
 
-       silc_auth_payload_free(auth);
+       founder_key = channel->founder_key;
+       fkey = silc_pkcs_public_key_encode(founder_key, &fkey_len);
+        if (!fkey) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                               SILC_STATUS_ERR_AUTH_FAILED,
+                                               0);
+         goto out;
+        }
       }
     }
   } else {
@@ -4215,10 +4277,7 @@ SILC_SERVER_CMD_FUNC(cmode)
       if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
        if (channel->founder_key)
          silc_pkcs_public_key_free(channel->founder_key);
-       if (channel->founder_passwd) {
-         silc_free(channel->founder_passwd);
-         channel->founder_passwd = NULL;
-       }
+       channel->founder_key = NULL;
       }
     }
   }
@@ -4229,13 +4288,14 @@ SILC_SERVER_CMD_FUNC(cmode)
   /* Send CMODE_CHANGE notify. */
   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
-                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 5,
+                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 6,
                                     cidp->data, cidp->len, 
                                     tmp_mask, 4,
                                     cipher, cipher ? strlen(cipher) : 0,
                                     hmac, hmac ? strlen(hmac) : 0,
                                     passphrase, passphrase ? 
-                                    strlen(passphrase) : 0);
+                                    strlen(passphrase) : 0,
+                                    fkey, fkey_len);
 
   /* Set CMODE notify type to network */
   if (!server->standalone)
@@ -4243,7 +4303,7 @@ SILC_SERVER_CMD_FUNC(cmode)
                                  server->server_type == SILC_ROUTER ? 
                                  TRUE : FALSE, channel,
                                  mode_mask, client->id, SILC_ID_CLIENT,
-                                 cipher, hmac, passphrase);
+                                 cipher, hmac, passphrase, founder_key);
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
@@ -4257,6 +4317,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   silc_buffer_free(cidp);
 
  out:
+  silc_free(fkey);
   silc_free(channel_id);
   silc_server_command_free(cmd);
 }
@@ -4279,6 +4340,9 @@ SILC_SERVER_CMD_FUNC(cumode)
   SilcUInt32 target_mask, sender_mask = 0, tmp_len, tmp_ch_len;
   int notify = FALSE;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
+  SilcPublicKey founder_key = NULL;
+  unsigned char *fkey = NULL;
+  SilcUInt32 fkey_len = 0;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CUMODE, cmd, 3, 4);
 
@@ -4390,40 +4454,57 @@ SILC_SERVER_CMD_FUNC(cumode)
     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
       /* The client tries to claim the founder rights. */
       unsigned char *tmp_auth;
-      SilcUInt32 tmp_auth_len, auth_len;
-      void *auth;
-      
+      SilcUInt32 tmp_auth_len;
+      SilcChannelClientEntry chl2;
+      SilcHashTableList htl;
+
       if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
          !channel->founder_key || !idata->public_key ||
          !silc_pkcs_public_key_compare(channel->founder_key, 
                                        idata->public_key)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                             SILC_STATUS_ERR_NOT_YOU, 0);
+                                             SILC_STATUS_ERR_AUTH_FAILED, 0);
        goto out;
       }
 
       tmp_auth = silc_argument_get_arg_type(cmd->args, 4, &tmp_auth_len);
       if (!tmp_auth) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+                                             SILC_STATUS_ERR_AUTH_FAILED, 0);
        goto out;
       }
 
-      auth = (channel->founder_method == SILC_AUTH_PASSWORD ?
-             (void *)channel->founder_passwd : (void *)channel->founder_key);
-      auth_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
-                 channel->founder_passwd_len : 0);
-      
-      if (!silc_auth_verify_data(tmp_auth, tmp_auth_len,
-                                channel->founder_method, auth, auth_len,
-                                idata->hash, client->id, SILC_ID_CLIENT)) {
+      /* Verify the authentication payload */
+      if (!silc_auth_verify_data(tmp_auth, tmp_auth_len, SILC_AUTH_PUBLIC_KEY,
+                                channel->founder_key, 0, server->sha1hash,
+                                client->id, SILC_ID_CLIENT)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                              SILC_STATUS_ERR_AUTH_FAILED, 0);
        goto out;
       }
-      
-      sender_mask = chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
+
       notify = TRUE;
+      founder_key = channel->founder_key;
+      fkey = silc_pkcs_public_key_encode(founder_key, &fkey_len);
+      if (!fkey) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                             SILC_STATUS_ERR_AUTH_FAILED, 0);
+       goto out;
+      }
+
+      /* 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);
+
+      sender_mask = chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
     }
   } else {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
@@ -4442,12 +4523,12 @@ SILC_SERVER_CMD_FUNC(cumode)
   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
     /* Promote to operator */
     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
-      if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
-         !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV,
-                                             0);
-       goto out;
+      if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) && 
+          !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                              SILC_STATUS_ERR_NO_CHANNEL_PRIV,
+                                              0);
+        goto out;
       }
 
       chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
@@ -4456,13 +4537,13 @@ SILC_SERVER_CMD_FUNC(cumode)
   } else {
     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
       if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
-         !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV,
-                                             0);
-       goto out;
+          !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
+        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,   
+                                              SILC_STATUS_ERR_NO_CHANNEL_PRIV,
+                                              0);
+        goto out;
       }
-
+      
       /* Demote to normal user */
       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
       notify = TRUE;
@@ -4541,16 +4622,39 @@ SILC_SERVER_CMD_FUNC(cumode)
     }
   }
 
+  if (target_mask & SILC_CHANNEL_UMODE_QUIET) {
+    if (!(chl->mode & SILC_CHANNEL_UMODE_QUIET)) {
+      if (client == target_client) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                             SILC_STATUS_ERR_PERM_DENIED, 0);
+       goto out;
+      }
+      chl->mode |= SILC_CHANNEL_UMODE_QUIET;
+      notify = TRUE;
+    }
+  } else {
+    if (chl->mode & SILC_CHANNEL_UMODE_QUIET) {
+      if (client == target_client) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                             SILC_STATUS_ERR_PERM_DENIED, 0);
+       goto out;
+      }
+      chl->mode &= ~SILC_CHANNEL_UMODE_QUIET;
+      notify = TRUE;
+    }
+  }
+
   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
   tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
 
   /* Send notify to channel, notify only if mode was actually changed. */
   if (notify) {
     silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
-                                      SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+                                      SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
                                       idp->data, idp->len,
                                       tmp_mask, 4, 
-                                      tmp_id, tmp_len);
+                                      tmp_id, tmp_len,
+                                      fkey, fkey_len);
 
     /* Set CUMODE notify type to network */
     if (!server->standalone)
@@ -4559,7 +4663,7 @@ SILC_SERVER_CMD_FUNC(cumode)
                                     TRUE : FALSE, channel,
                                     target_mask, client->id, 
                                     SILC_ID_CLIENT,
-                                    target_client->id);
+                                    target_client->id, founder_key);
   }
 
   /* Send command reply to sender */
@@ -4577,6 +4681,7 @@ SILC_SERVER_CMD_FUNC(cumode)
   silc_buffer_free(idp);
 
  out:
+  silc_free(fkey);
   silc_server_command_free(cmd);
 }
 
@@ -4851,13 +4956,19 @@ SILC_TASK_CALLBACK(silc_server_command_detach_cb)
 SILC_TASK_CALLBACK(silc_server_command_detach_timeout)
 {
   QuitInternal q = (QuitInternal)context;
-  SilcClientEntry client = (SilcClientEntry)q->sock;
+  SilcClientID *client_id = (SilcClientID *)q->sock;
+  SilcClientEntry client;
 
   SILC_LOG_DEBUG(("Start"));
 
-  if (client->mode & SILC_UMODE_DETACHED)
+  client = silc_idlist_find_client_by_id(q->server->local_list, client_id,
+                                        FALSE, NULL);
+
+  if (client && client->mode & SILC_UMODE_DETACHED)
     silc_server_free_client_data(q->server, NULL, client, TRUE,
                                 "Detach timeout");
+
+  silc_free(client_id);
   silc_free(q);
 }
 
@@ -4873,8 +4984,7 @@ SILC_SERVER_CMD_FUNC(detach)
 
   if (server->config->detach_disabled) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_DETACH,
-                                         SILC_STATUS_ERR_UNKNOWN_COMMAND,
-                                         0);
+                                         SILC_STATUS_ERR_UNKNOWN_COMMAND, 0);
     goto out;
   }
 
@@ -4886,10 +4996,13 @@ SILC_SERVER_CMD_FUNC(detach)
   /* Send the user mode notify to notify that client is detached */
   client->mode |= SILC_UMODE_DETACHED;
   client->data.status &= ~SILC_IDLIST_STATUS_RESUMED;
+  client->last_command = 0;
+  client->fast_command = 0;
   if (!server->standalone)
     silc_server_send_notify_umode(server, server->router->connection,
                                  server->server_type == SILC_SERVER ?
                                  FALSE : TRUE, client->id, client->mode);
+  server->stat.my_detached++;
 
   /* Check if anyone is watching this nickname */
   if (server->server_type == SILC_ROUTER)
@@ -4905,7 +5018,7 @@ SILC_SERVER_CMD_FUNC(detach)
   if (server->config->detach_timeout) {
     q = silc_calloc(1, sizeof(*q));
     q->server = server;
-    q->sock = (void *)client;
+    q->sock = silc_id_dup(client->id, SILC_ID_CLIENT);
     silc_schedule_task_add(server->schedule, 0, 
                           silc_server_command_detach_timeout,
                           q, server->config->detach_timeout * 60,
@@ -5077,6 +5190,17 @@ SILC_SERVER_CMD_FUNC(watch)
       silc_free(tmp);
   }
 
+  /* Distribute the watch list to backup routers too */
+  if (server->backup) {
+    SilcBuffer tmpbuf;
+    silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+    tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+    silc_server_backup_send(server, NULL, SILC_PACKET_COMMAND,
+                           cmd->packet->flags, tmpbuf->data, tmpbuf->len,
+                           FALSE, TRUE);
+    silc_buffer_free(tmpbuf);
+  }
+
   silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
                                        SILC_STATUS_OK, 0);
 
@@ -5446,7 +5570,8 @@ SILC_SERVER_CMD_FUNC(users)
     channel = silc_idlist_find_channel_by_name(server->local_list, 
                                               channel_name, NULL);
 
-  if (!channel || channel->disabled || !channel->users_resolved) {
+  if (!channel || (!server->standalone && (channel->disabled || 
+                   !channel->users_resolved))) {
     if (server->server_type != SILC_ROUTER && !server->standalone &&
        !cmd->pending) {
       SilcBuffer tmpbuf;
@@ -5499,8 +5624,12 @@ SILC_SERVER_CMD_FUNC(users)
   }
 
   /* Get the users list */
-  silc_server_get_users_on_channel(server, channel, &client_id_list,
-                                  &client_mode_list, &list_count);
+  if (!silc_server_get_users_on_channel(server, channel, &client_id_list,
+                                       &client_mode_list, &list_count)) {
+    list_count = 0;
+    client_id_list = NULL;
+    client_mode_list = NULL;
+  }
 
   /* List count */
   SILC_PUT32_MSB(list_count, lc);
@@ -5511,17 +5640,23 @@ SILC_SERVER_CMD_FUNC(users)
                                                SILC_STATUS_OK, 0, ident, 4,
                                                2, idp->data, idp->len,
                                                3, lc, 4,
-                                               4, client_id_list->data,
-                                               client_id_list->len,
-                                               5, client_mode_list->data,
-                                               client_mode_list->len);
+                                               4, client_id_list ? 
+                                               client_id_list->data : NULL,
+                                               client_id_list ?
+                                               client_id_list->len : 0,
+                                               5, client_mode_list ?
+                                               client_mode_list->data : NULL,
+                                               client_mode_list ?
+                                               client_mode_list->len : 0);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
     
   silc_buffer_free(idp);
   silc_buffer_free(packet);
-  silc_buffer_free(client_id_list);
-  silc_buffer_free(client_mode_list);
+  if (client_id_list)
+    silc_buffer_free(client_id_list);
+  if (client_mode_list)
+    silc_buffer_free(client_mode_list);
   silc_free(id);
 
  out: