diff -a -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/daemon/common/commonNetwork.ml ./src/daemon/common/commonNetwork.ml
--- ./src/daemon/common/commonNetwork.ml	2006-04-08 03:27:29.000000000 +0200
+++ ./src/daemon/common/commonNetwork.ml	2006-05-24 17:37:42.000000000 +0200
@@ -195,7 +195,7 @@
 let escape_char c = (List.assq c !network_escape_chars) ()
 *)
   
-let network_commands = ref ([] : (string * string * CommonTypes.arg_kind * string) list)
+let network_commands = ref ([] : (string * string * CommonTypes.cmd_type list * CommonTypes.arg_kind * string) list)
 
 let commands_by_kind = Hashtbl.create 11
 
@@ -207,7 +207,7 @@
      )
   
 let register_commands list = 
-  List.iter (fun (s, n, f, h) ->
+  List.iter (fun (s, n, t, f, h) ->
       try
         let ss = Hashtbl.find commands_by_kind n in
         ss := (s,h) :: !ss
diff -a -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/daemon/common/commonNetwork.mli ./src/daemon/common/commonNetwork.mli
--- ./src/daemon/common/commonNetwork.mli	2005-12-16 21:56:31.000000000 +0100
+++ ./src/daemon/common/commonNetwork.mli	2006-05-24 17:37:42.000000000 +0200
@@ -43,8 +43,8 @@
 val networks_for_all : (CommonTypes.network -> bool) -> bool
 val network_find_by_name : string -> CommonTypes.network
 val network_find_by_num : int -> CommonTypes.network
-val network_commands : (string * string * CommonTypes.arg_kind * string) list ref
-val register_commands : (string * string * CommonTypes.arg_kind * string) list -> unit
+val network_commands : (string * string * CommonTypes.cmd_type list * CommonTypes.arg_kind * string) list ref
+val register_commands : (string * string * CommonTypes.cmd_type list * CommonTypes.arg_kind * string) list -> unit
 val network_connect_servers : CommonTypes.network -> unit
 val network_forget_search : CommonTypes.network -> CommonTypes.search -> unit
 val network_close_search : CommonTypes.network -> CommonTypes.search -> unit
diff -a -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/daemon/common/commonTypes.ml ./src/daemon/common/commonTypes.ml
--- ./src/daemon/common/commonTypes.ml	2006-05-17 10:52:43.000000000 +0200
+++ ./src/daemon/common/commonTypes.ml	2006-05-24 19:11:08.000000000 +0200
@@ -844,6 +844,34 @@
 | Arg_two of (string -> string -> arg_handler)
 | Arg_three of (string -> string -> string -> arg_handler)
 
+type cmd_type =
+(* cmd_type(s) can be attached to commands, access to each command group
+   represented by a cmd_type has to be activated in groups config.
+   Admin type users have access to all commands.
+   If no cmd_type is attached to a command, this command is available
+   for admin type users (group_admin true) only, *)
+
+(* commands for users belonging to groups with group_server_admin = true *)
+(* this group includes all commands to add/remove/connect/disconnect/rename
+   servers/nodes, also includes all commands regarding friends *)
+  Cmd_server
+
+(* commands for users belonging to groups with group_uploads = true *)
+| Cmd_upload
+
+(* commands for users belonging to groups with group_downloader = true *)
+(* this group includes all commands to start/pause/resume/cancel/commit
+   downloads, also searching for files
+   A .torrent file copied into ./torrents/incoming belonging to a user
+   without this right will be ignored. *)
+| Cmd_download
+
+(* commands for users belonging to groups with group_statistic = true *)
+| Cmd_stat
+(* commands for users belonging to groups with group_read_only = true *)
+| Cmd_read_only
+(* commands for all users *)
+| Cmd_all
     
 let string_of_kind kind =
   try
diff -a -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/daemon/driver/driverCommands.ml ./src/daemon/driver/driverCommands.ml
--- ./src/daemon/driver/driverCommands.ml	2006-05-23 19:38:26.000000000 +0200
+++ ./src/daemon/driver/driverCommands.ml	2006-05-24 19:20:22.000000000 +0200
@@ -72,22 +72,32 @@
 
 let execute_command arg_list output cmd args =
   let buf = output.conn_buf in
+  let user = output.conn_user.ui_user_name in
+  let command_allowed cmd_types = true
+  in
   try
     let rec iter list =
       match list with
         [] ->
           Gettext.buftext buf no_such_command cmd
-      | (command, _, arg_kind, help) :: tail ->
+      | (command, _, cmd_types, arg_kind, help) :: tail ->
           if command = cmd then
-            Buffer.add_string buf (
-              match arg_kind, args with
-                Arg_none f, [] -> f output
-              | Arg_multiple f, _ -> f args output
-              | Arg_one f, [arg] -> f arg  output
-              | Arg_two f, [a1;a2] -> f a1 a2 output
-              | Arg_three f, [a1;a2;a3] -> f a1 a2 a3 output
-              | _ -> bad_number_of_args
-            )
+            if command_allowed cmd_types then
+              Buffer.add_string buf (
+                match arg_kind, args with
+                  Arg_none f, [] -> f output
+                | Arg_multiple f, _ -> f args output
+                | Arg_one f, [arg] -> f arg  output
+                | Arg_two f, [a1;a2] -> f a1 a2 output
+                | Arg_three f, [a1;a2;a3] -> f a1 a2 a3 output
+                | _ -> bad_number_of_args
+              )
+            else
+              if use_html_mods output then
+                html_mods_table_one_row buf "upstatsTable" "upstats" [
+                  ("", "srh", Printf.sprintf "You are not allowed to use command %s" cmd) ]
+              else
+                Printf.bprintf buf "You are not allowed to use command %s\n" cmd
           else
             iter tail
     in
@@ -248,7 +258,7 @@
 let register_commands section list =
   register_commands
     (List2.tail_map
-      (fun (cmd, action, desc) -> (cmd, section, action, _s desc)) list)
+      (fun (cmd, cmd_type, action, desc) -> (cmd, section, cmd_type, action, _s desc)) list)
 
 
 (*************************************************************************)
@@ -262,12 +272,12 @@
   register_commands "Driver/General"
     [
 
-    "dump_heap", Arg_none (fun o ->
+    "dump_heap", [], Arg_none (fun o ->
 (*        Gc.dump_heap (); *)
         "heap dumped"
     ), ":\t\t\t\tdump heap for debug";
 
-    "alias", Arg_multiple ( fun args o ->
+    "alias", [], Arg_multiple ( fun args o ->
         let out = ref "" in
 	if List.length args = 0 then begin
 	  out := "List of aliases\n\n";
@@ -299,7 +309,7 @@
        ^"\t\t\t\t\tfor example: \"alias ca vd\"$n";
 
 
-    "unalias", Arg_one (
+    "unalias", [], Arg_one (
       fun arg o ->
 	(try
 	   let old_def = List.assoc arg !!alias_commands in
@@ -310,28 +320,23 @@
     ), ":\t\t\t\t$bdelete a command alias\n"
        ^"\t\t\t\t\texample: \"unalias ca\"$n";
 
-    "q", Arg_none (fun o ->
+    "q", [Cmd_all], Arg_none (fun o ->
         raise CommonTypes.CommandCloseSocket
     ), ":\t\t\t\t\t$bclose telnet$n";
 
-    "kill", Arg_none (fun o ->
-        if o.conn_user == default_user then
-	  begin
-            CommonInteractive.clean_exit 0;
-	    _s "exit"
-	  end
-        else
-          _s "Only 'admin' is allowed to kill MLDonkey"
+    "kill", [], Arg_none (fun o ->
+        CommonInteractive.clean_exit 0;
+	_s "exit"
         ), ":\t\t\t\t\t$bsave and kill the server$n";
 
-    "urladd", Arg_two (fun kind url o ->
+    "urladd", [], Arg_two (fun kind url o ->
 	web_infos_add kind 1 url;
 	CommonWeb.load_url true kind url;
         "url added to web_infos. downloading now"
     ), "<kind> <url> :\t\t\tload this file from the web\n"
        ^"\t\t\t\t\tkind is either server.met (if the downloaded file is a server.met)";
 
-    "urlremove", Arg_one (fun url o ->
+    "urlremove", [], Arg_one (fun url o ->
     	if web_infos_exists url then
 	  begin
 	    web_infos_remove [("",0,url)];
@@ -341,7 +346,7 @@
             "URL does not exists in web_infos"
     ), "<url> :\t\t\tremove URL from web_infos";
 
-    "recover_temp", Arg_none (fun o ->
+    "recover_temp", [Cmd_download], Arg_none (fun o ->
         networks_iter (fun r ->
             try
               CommonNetwork.network_recover_temp r
@@ -356,7 +361,7 @@
         _s ""
     ), ":\t\t\t\trecover lost files from temp directory";
 
-    "vc", Arg_multiple (fun args o ->
+    "vc", [Cmd_stat;Cmd_download], Arg_multiple (fun args o ->
         if args = ["all"] then begin
             let buf = o.conn_buf in
 
@@ -404,7 +409,7 @@
         ""
     ), "<num> :\t\t\t\tview client (use arg 'all' for all clients)";
 
-    "version", Arg_none (fun o ->
+    "version", [Cmd_all], Arg_none (fun o ->
         let buf = o.conn_buf in
         let version = CommonGlobals.version () in
         if o.conn_output = HTML then
@@ -420,7 +425,7 @@
         ""
     ), ":\t\t\t\tprint mldonkey version";
 
-    "uptime", Arg_none (fun o ->
+    "uptime", [Cmd_stat], Arg_none (fun o ->
         let buf = o.conn_buf in
         let uptime = log_time () ^ "- up " ^
 	  Date.time_to_string (last_time () - start_time) "verbose" in
@@ -437,7 +442,7 @@
         ""
     ), ":\t\t\t\tcore uptime";
 
-    "sysinfo", Arg_none (fun o ->
+    "sysinfo", [Cmd_stat], Arg_none (fun o ->
 	let buf = o.conn_buf in
         ignore(buildinfo (o.conn_output = HTML) buf);
         if o.conn_output = HTML then Printf.bprintf buf "\\<P\\>";
@@ -447,25 +452,25 @@
         ""
     ), ":\t\t\t\tprint mldonkey core build, runtime and disk information";
 
-    "buildinfo", Arg_none (fun o ->
+    "buildinfo", [Cmd_stat], Arg_none (fun o ->
 	let buf = o.conn_buf in
         ignore(buildinfo (o.conn_output = HTML) buf);
         ""
     ), ":\t\t\t\tprint mldonkey core build information";
 
-    "runinfo", Arg_none (fun o ->
+    "runinfo", [Cmd_stat], Arg_none (fun o ->
 	let buf = o.conn_buf in
         ignore(runinfo (o.conn_output = HTML) buf o);
         ""
     ), ":\t\t\t\tprint mldonkey runtime information";
 
-    "diskinfo", Arg_none (fun o ->
+    "diskinfo", [Cmd_stat], Arg_none (fun o ->
 	let buf = o.conn_buf in
         ignore(diskinfo (o.conn_output = HTML) buf);
         ""
     ), ":\t\t\t\tprint mldonkey disk information";
 
-    "activity", Arg_one (fun arg o ->
+    "activity", [Cmd_stat], Arg_one (fun arg o ->
         let arg = int_of_string arg in
         let buf = o.conn_buf in
         let activity_begin = last_time () - arg * 60 in
@@ -488,7 +493,7 @@
         ""
     ), "<minutes> :\t\t\tprint activity in the last <minutes> minutes";
 
-    "message_log", Arg_multiple (fun args o ->
+    "message_log", [Cmd_download;Cmd_stat], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         let counter = ref 0 in
 
@@ -547,7 +552,7 @@
         ""
     ), ":\t\t\t\tmessage_log [refresh delay in seconds]";
 
-    "message", Arg_multiple (fun args o ->
+    "message", [Cmd_download], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         match args with
           n :: msglist ->
@@ -627,7 +632,7 @@
 
     ), ":\t\t\t\t[<client num> <msg>]";
 
-    "useradd", Arg_multiple (fun args o ->
+    "useradd", [], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
 	let print_result o result =
           if o.conn_output = HTML then
@@ -637,29 +642,25 @@
             Printf.bprintf buf "%s" result
 	in
 	let add_new_user user pass mail =
-          if o.conn_user == default_user
-	    || o.conn_user == (find_ui_user user) then
-	    try
-	      ignore (user2_find user);
-	      ignore (user2_add user (Md4.string pass) "");
-	      print_result o (Printf.sprintf "Password of user %s changed" user)
-            with _ ->
-	      ignore (user2_add user (Md4.string pass) "");
-	      print_result o (Printf.sprintf "User %s added" user)
-          else
-	    print_result o "Only 'admin' is allowed to add users"
+	  try
+	    ignore (user2_find user);
+	    ignore (user2_add user (Md4.string pass) "");
+	    print_result o (Printf.sprintf "Password of user %s changed" user)
+          with _ ->
+	    ignore (user2_add user (Md4.string pass) "");
+	    print_result o (Printf.sprintf "User %s added" user)
 	in begin
         match args with
 	  user :: pass :: mail :: _ ->
 	    add_new_user user pass mail
 	| user :: pass :: _ ->
-	    add_new_user user pass "";
+	    add_new_user user pass ""
 	| _ -> print_result o "Wrong syntax: use 'useradd user pass <mail>'"
 	end;
 	_s ""
     ), "<user> <passwd> [<mail>] :\t\tadd new mldonkey user/change user password";
 
-    "userdel", Arg_one (fun user o ->
+    "userdel", [], Arg_one (fun user o ->
         let buf = o.conn_buf in
 	let print_result o result =
           if o.conn_output = HTML then
@@ -668,25 +669,20 @@
           else
             Printf.bprintf buf "%s" result
 	in
-        if o.conn_user == default_user then
-	  if user = admin_user then
-	    print_result o "User 'admin' can not be removed"
-	  else
-	    try
-	      ignore (user2_find user);
-	      ignore (user2_remove user);
-              print_result o (Printf.sprintf "User %s removed" user)
-            with _ ->
-              print_result o (Printf.sprintf "User %s not found" user)
-        else
-          print_result o "Only 'admin' is allowed to remove users";
+	if user = admin_user then
+	  print_result o "User 'admin' can not be removed"
+	else
+          begin try
+	    ignore (user2_find user);
+	    ignore (user2_remove user);
+            print_result o (Printf.sprintf "User %s removed" user)
+          with _ ->
+            print_result o (Printf.sprintf "User %s not found" user)
+          end;
 	_s ""
     ), "<user> :\t\t\tremove a mldonkey user";
 
-
-    "users", Arg_none (fun o ->
-        if o.conn_user == default_user then
-
+    "users", [], Arg_none (fun o ->
         let buf = o.conn_buf in
 
         if use_html_mods o then begin
@@ -741,11 +737,9 @@
                 user.user_name);
           end;
         ""
-        else
-          _s "Only 'admin' is allowed to list users"
     ), ":\t\t\t\t\tprint users";
 
-    "whoami", Arg_none (fun o ->
+    "whoami", [Cmd_all], Arg_none (fun o ->
         let buf = o.conn_buf in
 	let whoami = o.conn_user.ui_user_name in
         if use_html_mods o then
@@ -756,7 +750,7 @@
         _s ""
     ), ":\t\t\t\tprint logged-in user name";
 
-    "calendar_add", Arg_two (fun hour action o ->
+    "calendar_add", [], Arg_two (fun hour action o ->
         let buf = o.conn_buf in
         calendar =:= ([0;1;2;3;4;5;6], [int_of_string hour], action)
         :: !!calendar;
@@ -768,7 +762,7 @@
         _s ""
     ), "<hour> \"<command>\" :\tadd a command to be executed every day";
 
-    "vcal", Arg_none (fun o ->
+    "vcal", [], Arg_none (fun o ->
         let buf = o.conn_buf in
         if use_html_mods o then begin
             Printf.bprintf buf "\\<div class=\\\"vo\\\"\\>
@@ -801,7 +795,7 @@
   register_commands "Driver/Servers"
     [
 
-    "vm", Arg_none (fun o ->
+    "vm", [Cmd_server], Arg_none (fun o ->
         let buf = o.conn_buf in
         if use_html_mods o then Printf.bprintf buf
             "\\<div class=\\\"servers\\\"\\>\\<table align=center border=0 cellspacing=0 cellpadding=0\\>\\<tr\\>\\<td\\>";
@@ -809,7 +803,7 @@
         if use_html_mods o then Printf.bprintf buf "\\</td\\>\\</tr\\>\\</table\\>\\</div\\>";
         ""), ":\t\t\t\t\t$blist connected servers$n";
 
-    "vma", Arg_none (fun o ->
+    "vma", [Cmd_server], Arg_none (fun o ->
         let buf = o.conn_buf in
         html_mods_cntr_init ();
         let nb_servers = ref 0 in
@@ -846,7 +840,7 @@
           end;
     ""), ":\t\t\t\t\tlist all known servers";
 
-    "rem", Arg_multiple (fun args o ->
+    "rem", [Cmd_server], Arg_multiple (fun args o ->
         if args = ["all"] then
 	  begin
             Intmap.iter ( fun _ s ->
@@ -863,7 +857,7 @@
           end
     ), "<server numbers> :\t\t\tremove server (use arg 'all' for all servers)";
 
-    "server_banner", Arg_one (fun num o ->
+    "server_banner", [Cmd_server], Arg_one (fun num o ->
         let num = int_of_string num in
         let s = server_find num in
         (match server_state s with
@@ -872,7 +866,7 @@
         ""
     ), "<num> :\t\t\tprint banner of connected server <num>";
 
-    "c", Arg_multiple (fun args o ->
+    "c", [Cmd_server], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         match args with
           [] ->
@@ -899,7 +893,7 @@
         ""
     ), "[<num>] :\t\t\t\tconnect to more servers (or to server <num>)";
 
-    "x", Arg_one (fun num o ->
+    "x", [Cmd_server], Arg_one (fun num o ->
         let num = int_of_string num in
         let s = server_find num in
         (match server_state s with
@@ -920,27 +914,27 @@
   register_commands "Driver/Friends"
     [
 
-    "vfr", Arg_none (fun o ->
+    "vfr", [Cmd_server], Arg_none (fun o ->
         List.iter (fun c ->
             client_print c o) !!friends;
         ""
     ), ":\t\t\t\t\tview friends";
 
-    "gfr", Arg_one (fun num o ->
+    "gfr", [Cmd_server], Arg_one (fun num o ->
         let num = int_of_string num in
         let c = client_find num in
         client_browse c true;
         _s "client browse"
     ), "<client num> :\t\t\task friend files";
 
-    "friend_add", Arg_one (fun num o ->
+    "friend_add", [Cmd_server], Arg_one (fun num o ->
         let num = int_of_string num in
         let c = client_find num in
         friend_add c;
         _s "Added friend"
     ), "<client num> :\t\tadd client <client num> to friends";
 
-    "friend_remove", Arg_multiple (fun args o ->
+    "friend_remove", [Cmd_server], Arg_multiple (fun args o ->
         if args = ["all"] then begin
             List.iter (fun c ->
                 friend_remove c
@@ -956,7 +950,7 @@
           end
     ), "<client numbers> :\tremove friend (use arg 'all' for all friends)";
 
-    "friends", Arg_none (fun o ->
+    "friends", [Cmd_server], Arg_none (fun o ->
         let buf = o.conn_buf in
 
         if use_html_mods o then begin
@@ -1041,7 +1035,7 @@
         ""
     ), ":\t\t\t\tdisplay all friends";
 
-    "files", Arg_one (fun arg o ->
+    "files", [Cmd_server], Arg_one (fun arg o ->
         let buf = o.conn_buf in
         let n = int_of_string arg in
         List.iter (fun c ->
@@ -1074,7 +1068,7 @@
   register_commands "Driver/Network"
     [
 
-    "nu", Arg_one (fun num o ->
+    "nu", [], Arg_one (fun num o ->
         let num = int_of_string num in
 
         if num > 0 then (* we want to disable upload for a short time *)
@@ -1099,7 +1093,7 @@
         else ""
     ), "<m> :\t\t\t\tdisable upload during <m> minutes (multiple of 5)";
 
-    "bw_stats", Arg_multiple (fun args o ->
+    "bw_stats", [Cmd_stat], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         if use_html_mods o then
           begin
@@ -1140,14 +1134,14 @@
         ""
     ), ":\t\t\t\tprint current bandwidth stats";
 
-    "stats", Arg_none (fun o ->
+    "stats", [Cmd_stat], Arg_none (fun o ->
         let buf = o.conn_buf in
         CommonInteractive.network_display_stats buf o;
         if use_html_mods o then
           print_gdstats buf o;
       _s ""), ":\t\t\t\t\tdisplay transfer statistics";
 
-    "gdstats", Arg_none (fun o ->
+    "gdstats", [Cmd_stat], Arg_none (fun o ->
         let buf = o.conn_buf in
 	if Autoconf.has_gd then
           if use_html_mods o then
@@ -1158,7 +1152,7 @@
 	  Printf.bprintf buf "Gd support was not compiled";
       _s ""), ":\t\t\t\tdisplay graphical transfer statistics";
 
-    "gdremove", Arg_none (fun o ->
+    "gdremove", [Cmd_stat], Arg_none (fun o ->
         let buf = o.conn_buf in
 	if Autoconf.has_gd then
 	  begin
@@ -1169,7 +1163,7 @@
 	  Printf.bprintf buf "Gd support was not compiled";
       _s ""), ":\t\t\t\tremove graphical transfer statistics files";
 
-    "!", Arg_multiple (fun arg o ->
+    "!", [], Arg_multiple (fun arg o ->
         if !!allow_any_command then
           match arg with
             c :: tail ->
@@ -1210,19 +1204,19 @@
   register_commands "Driver/Networks"
     [
 
-    "networks", Arg_none (fun o ->
+    "networks", [Cmd_stat], Arg_none (fun o ->
         let buf = o.conn_buf in
         print_network_modules buf o;
         ""
     ) , ":\t\t\t\tprint all networks";
 
-    "enable", Arg_one (fun num o ->
+    "enable", [], Arg_one (fun num o ->
         let n = network_find_by_num (int_of_string num) in
         network_enable n;
         _s "network enabled"
     ) , "<num> :\t\t\t\tenable a particular network";
 
-    "disable", Arg_one (fun num o ->
+    "disable", [], Arg_one (fun num o ->
         let n = network_find_by_num (int_of_string num) in
         network_disable n;
         _s "network disabled"
@@ -1240,7 +1234,7 @@
   register_commands "Driver/Searches"
     [
 
-    "forget", Arg_multiple (fun args o ->
+    "forget", [Cmd_download], Arg_multiple (fun args o ->
         let user = o.conn_user in
         begin
           match args with
@@ -1266,7 +1260,7 @@
         ""
     ), "<num1> <num2> ... :\t\tforget searches <num1> <num2> ...";
 
-    "vr", Arg_multiple (fun args o ->
+    "vr", [Cmd_download], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         let user = o.conn_user in
         match args with
@@ -1292,7 +1286,7 @@
             end;
     ), "[<num>] :\t\t\t\t$bview results of a search$n";
 
-    "s", Arg_multiple (fun args o ->
+    "s", [Cmd_download], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         let user = o.conn_user in
         let query, net = CommonSearch.search_of_args args in
@@ -1307,7 +1301,7 @@
         ""
     ), "<query> :\t\t\t\t$bsearch for files on all networks$n\n\n\tWith special args:\n\t-network <netname>\n\t-minsize <size>\n\t-maxsize <size>\n\t-media <Video|Audio|...>\n\t-Video\n\t-Audio\n\t-format <format>\n\t-title <word in title>\n\t-album <word in album>\n\t-artist <word in artist>\n\t-field <field> <fieldvalue>\n\t-not <word>\n\t-and <word>\n\t-or <word>\n";
 
-    "ls", Arg_multiple (fun args o ->
+    "ls", [Cmd_download], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         let user = o.conn_user in
         let query, net = CommonSearch.search_of_args args in
@@ -1322,7 +1316,7 @@
         ""
     ), "<query> :\t\t\t\tsearch for files locally\n\n\tWith special args:\n\t-network <netname>\n\t-minsize <size>\n\t-maxsize <size>\n\t-media <Video|Audio|...>\n\t-Video\n\t-Audio\n\t-format <format>\n\t-title <word in title>\n\t-album <word in album>\n\t-artist <word in artist>\n\t-field <field> <fieldvalue>\n\t-not <word>\n\t-and <word>\n\t-or <word>\n";
 
-    "vs", Arg_none (fun o ->
+    "vs", [Cmd_download], Arg_none (fun o ->
         let buf = o.conn_buf in
         let user = o.conn_user in
         let num_searches = List.length user.ui_user_searches in
@@ -1353,7 +1347,7 @@
         ""
     ), ":\t\t\t\t\tview all queries";
 
-    "view_custom_queries", Arg_none (fun o ->
+    "view_custom_queries", [Cmd_download], Arg_none (fun o ->
         let buf = o.conn_buf in
         if o.conn_output <> HTML then
           Printf.bprintf buf "%d custom queries defined\n"
@@ -1391,13 +1385,13 @@
         ""
     ), ":\t\t\tview custom queries";
 
-    "d", Arg_multiple (fun args o ->
+    "d", [Cmd_download], Arg_multiple (fun args o ->
         List.iter (fun arg ->
             CommonInteractive.download_file o arg) args;
         ""
     ), "<num> :\t\t\t\t$bfile to download$n";
 
-    "force_download", Arg_none (fun o ->
+    "force_download", [Cmd_download], Arg_none (fun o ->
 	if !forceable_download = [] then
 	  begin
             let output = (if o.conn_output = HTML then begin
@@ -1450,24 +1444,20 @@
   register_commands "Driver/Options"
     [
 
-    "set", Arg_two (fun name value o ->
-	if (o.conn_user == default_user) || !!enable_user_config then begin
-        try
+    "set", [], Arg_two (fun name value o ->
+	begin try
           try
             CommonInteractive.set_fully_qualified_options name value;
             Printf.sprintf "option %s value changed" name
-
           with _ ->
               Options.set_simple_option downloads_ini name value;
               Printf.sprintf "option %s value changed" name
         with e ->
             Printf.sprintf "Error %s" (Printexc2.to_string e)
-	  end
-	else
-	  _s "Only 'admin' is allowed to change options"
+	end
     ), "<option_name> <option_value> :\t$bchange option value$n";
 
-    "save", Arg_multiple (fun args o ->
+    "save", [], Arg_multiple (fun args o ->
         match args with
 	  ["options"] -> DriverInteractive.save_config (); _s "options saved"
 	| ["sources"] -> CommonComplexOptions.save_sources (); _s "sources saved"
@@ -1481,7 +1471,7 @@
 	       CommonComplexOptions.save_sources (); _s "options and sources saved"
         ), "[<options|sources|backup>] :\tsave options and/or sources or backup (empty for options and sources)";
 
-    "vo", Arg_none (fun o ->
+    "vo", [], Arg_none (fun o ->
         let buf = o.conn_buf in
         if use_html_mods o then begin
 
@@ -1538,7 +1528,7 @@
 
 
 
-    "voo", Arg_multiple (fun args o ->
+    "voo", [], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         if use_html_mods o then begin
 
@@ -1795,7 +1785,6 @@
                   | 8 ->
                       [
 			strings_of_option term_ansi;
-			strings_of_option enable_user_config;
 			strings_of_option messages_filter;
 			strings_of_option max_displayed_results;
 			strings_of_option max_name_len;
@@ -1862,7 +1851,7 @@
         ""
     ), ":\t\t\t\t\tprint all options";
 
-    "vwi", Arg_none (fun o ->
+    "vwi", [], Arg_none (fun o ->
         let buf = o.conn_buf in
         if use_html_mods o then begin
             Printf.bprintf buf "\\<div class=\\\"shares\\\"\\>\\<table class=main cellspacing=0 cellpadding=0\\>
@@ -1946,7 +1935,7 @@
         ""
     ), ":\t\t\t\t\tprint web_infos options";
 
-    "options", Arg_multiple (fun args o ->
+    "options", [], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         match args with
           [] ->
@@ -2009,7 +1998,7 @@
   register_commands "Driver/Sharing"
     [
 
-    "reshare", Arg_none (fun o ->
+    "reshare", [Cmd_upload], Arg_none (fun o ->
         let buf = o.conn_buf in
         shared_check_files ();
         if o.conn_output = HTML then
@@ -2020,7 +2009,7 @@
         _s ""
     ), ":\t\t\t\tcheck shared files for removal";
 
-     "debug_disk", Arg_one (fun arg o ->
+     "debug_disk", [], Arg_one (fun arg o ->
          let buf = o.conn_buf in
 	 let print_i64o = function
 	   | None -> "Unknown"
@@ -2050,7 +2039,7 @@
          _s ""
      ), "debug command (example: disk .)";
 
-     "debug_dir", Arg_one (fun arg o ->
+     "debug_dir", [], Arg_one (fun arg o ->
          let buf = o.conn_buf in
 	 let filelist = Unix2.list_directory arg in
          Printf.bprintf buf "%d entries in dir %s\n" (List.length filelist) arg;
@@ -2067,7 +2056,7 @@
          _s ""
      ), "debug command (example: disk .)";
 
-     "debug_fileinfo", Arg_one (fun arg o ->
+     "debug_fileinfo", [], Arg_one (fun arg o ->
          let buf = o.conn_buf in
 	 (try
 	    let s = Unix.stat arg in
@@ -2083,7 +2072,7 @@
          _s ""
      ), "debug command (example: file .)";
 
-     "debug_rlimit", Arg_none (fun o ->
+     "debug_rlimit", [], Arg_none (fun o ->
          let buf = o.conn_buf in
 	 let cpu = Unix2.ml_getrlimit Unix2.RLIMIT_CPU in
 	 let fsize = Unix2.ml_getrlimit Unix2.RLIMIT_FSIZE in
@@ -2108,7 +2097,7 @@
          _s ""
      ), "debug command";
 
-    "shares", Arg_none (fun o ->
+    "shares", [Cmd_upload], Arg_none (fun o ->
 
         let buf = o.conn_buf in
 
@@ -2191,7 +2180,7 @@
         ""
     ), ":\t\t\t\tprint shared directories";
 
-    "share", Arg_multiple (fun args o ->
+    "share", [Cmd_upload], Arg_multiple (fun args o ->
         let (prio, arg, strategy) = match args with
           | [prio; arg; strategy] -> int_of_string prio, arg, strategy
           | [prio; arg] -> int_of_string prio, arg, "only_directory"
@@ -2222,7 +2211,7 @@
           "no such directory"
     ), "<priority> <dir> [<strategy>] :\tshare directory <dir> with <priority> [and sharing strategy <strategy>]";
 
-    "unshare", Arg_one (fun arg o ->
+    "unshare", [Cmd_upload], Arg_one (fun arg o ->
 
         let found = ref false in
         shared_directories =:= List.filter (fun sd ->
@@ -2245,7 +2234,7 @@
 
     ), "<dir> :\t\t\t\tshare directory <dir>";
 
-    "upstats", Arg_none (fun o ->
+    "upstats", [Cmd_stat;Cmd_upload], Arg_none (fun o ->
         let buf = o.conn_buf in
 
         if use_html_mods o then begin
@@ -2355,7 +2344,7 @@
         _s ""
     ), ":\t\t\t\tstatistics on upload";
 
-    "links", Arg_none (fun o ->
+    "links", [Cmd_upload], Arg_none (fun o ->
         let buf = o.conn_buf in
         let list = ref [] in
         shared_iter (fun s ->
@@ -2380,7 +2369,7 @@
         "Done"
     ), ":\t\t\t\t\tlist links of shared files";
 
-    "uploaders", Arg_none (fun o ->
+    "uploaders", [Cmd_upload], Arg_none (fun o ->
         let buf = o.conn_buf in
 
         let nuploaders = Intmap.length !uploaders in
@@ -2566,7 +2555,7 @@
   register_commands "Driver/Downloads"
     [
 
-    "priority", Arg_multiple (fun args o ->
+    "priority", [Cmd_download], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         match args with
           p :: files ->
@@ -2591,7 +2580,7 @@
 
     ), "<priority> <files numbers> :\tchange file priorities";
 
-    "confirm", Arg_one (fun arg o ->
+    "confirm", [Cmd_download], Arg_one (fun arg o ->
         match String.lowercase arg with
           "yes" | "y" | "true" ->
             List.iter (fun file ->
@@ -2611,7 +2600,7 @@
         | _ -> failwith "Invalid argument"
     ), "<yes|no|what> :\t\t\tconfirm cancellation";
 
-    "test_recover", Arg_one (fun num o ->
+    "test_recover", [], Arg_one (fun num o ->
 
         let num = int_of_string num in
         let file = file_find num in
@@ -2627,7 +2616,7 @@
     ), "<num> :\t\t\tprint the segments downloaded in file";
 
 
-    "cancel", Arg_multiple (fun args o ->
+    "cancel", [Cmd_download], Arg_multiple (fun args o ->
 
         let file_cancel num =
           if not (List.memq num !to_cancel) then
@@ -2649,7 +2638,7 @@
         files_to_cancel o
     ), "<num> :\t\t\t\tcancel download (use arg 'all' for all files)";
 
-    "downloaders", Arg_none (fun o ->
+    "downloaders", [Cmd_download], Arg_none (fun o ->
         let buf = o.conn_buf in
 
         if use_html_mods o then
@@ -2684,7 +2673,7 @@
         ""
     ) , ":\t\t\t\tdisplay downloaders list";
 
-    "verify_chunks", Arg_multiple (fun args o ->
+    "verify_chunks", [Cmd_download], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         match args with
           [arg] ->
@@ -2703,7 +2692,7 @@
             _s "done"
     ), "<num> :\t\t\tverify chunks of file <num>";
 
-    "pause", Arg_multiple (fun args o ->
+    "pause", [Cmd_download], Arg_multiple (fun args o ->
         if args = ["all"] then
           List.iter (fun file ->
               file_pause file;
@@ -2718,7 +2707,7 @@
               ) !!files) args; ""
     ), "<num> :\t\t\t\tpause a download (use arg 'all' for all files)";
 
-    "resume", Arg_multiple (fun args o ->
+    "resume", [Cmd_download], Arg_multiple (fun args o ->
         if args = ["all"] then
           List.iter (fun file ->
               file_resume file
@@ -2733,7 +2722,7 @@
               ) !!files) args; ""
     ), "<num> :\t\t\t\tresume a paused download (use arg 'all' for all files)";
 
-    "commit", Arg_none (fun o ->
+    "commit", [Cmd_download], Arg_none (fun o ->
         List.iter (fun file ->
             file_commit file
         ) !!done_files;
@@ -2746,7 +2735,7 @@
         ""
     ) , ":\t\t\t\t$bmove downloaded files to incoming directory$n";
 
-    "vd", Arg_multiple (fun args o ->
+    "vd", [Cmd_download;Cmd_read_only], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         match args with
           | ["queued"] ->
@@ -2799,9 +2788,9 @@
             let list = List2.tail_map file_info !!files in
             DriverInteractive.display_file_list buf o list;
             ""
-    ), "<num> :\t\t\t\t$bview file info$n";
+    ), "[<num>|queued|paused|downloading] :\t\t\t\t$bview file info for download <num>, or lists of queued, paused or downloading files, or all downloads if no argument given$n";
 
-    "preview", Arg_one (fun arg o ->
+    "preview", [Cmd_download;Cmd_read_only], Arg_one (fun arg o ->
 
         let num = int_of_string arg in
         let file = file_find num in
@@ -2809,7 +2798,7 @@
         _s "done"
     ), "<file number> :\t\t\tstart previewer for file <file number>";
 
-    "rename", Arg_two (fun arg new_name o ->
+    "rename", [Cmd_download], Arg_two (fun arg new_name o ->
         let num = int_of_string arg in
         try
           let file = file_find num in
@@ -2818,12 +2807,12 @@
         with e -> Printf.sprintf (_b "No file number %d, error %s") num (Printexc2.to_string e)
     ), "<num> \"<new name>\" :\t\tchange name of download <num> to <new name>";
 
-    "dllink", Arg_multiple (fun args o ->
+    "dllink", [Cmd_download], Arg_multiple (fun args o ->
         let url = String2.unsplit args ' ' in
         dllink_parse (o.conn_output = HTML) url
         ), "<link> :\t\t\t\tdownload ed2k, sig2dat, torrent or other link";
 
-    "dllinks", Arg_one (fun arg o ->
+    "dllinks", [Cmd_download], Arg_one (fun arg o ->
 	let result = Buffer.create 100 in
         let file = File.to_string arg in
         let lines = String2.split_simplify file '\n' in
@@ -2848,18 +2837,18 @@
   register_commands "Driver/Xpert"
     [
 
-    "reload_messages", Arg_none (fun o ->
+    "reload_messages", [], Arg_none (fun o ->
         CommonMessages.load_message_file ();
         "\\<script type=\\\"text/javascript\\\"\\>top.window.location.reload();\\</script\\>"
     ), ":\t\t\treload messages file";
 
-    "log", Arg_none (fun o ->
+    "log", [], Arg_none (fun o ->
         let buf = o.conn_buf in
         log_to_buffer buf;
         _s "------------- End of log"
     ), ":\t\t\t\t\tdump current log state to console";
 
-    "ansi", Arg_one (fun arg o ->
+    "ansi", [], Arg_one (fun arg o ->
         let b = bool_of_string arg in
         if b then begin
             o.conn_output <- ANSI;
@@ -2868,7 +2857,7 @@
         _s "$rdone$n"
     ), ":\t\t\t\t\ttoggle ansi terminal (devel)";
 
-    "term", Arg_two (fun w h o ->
+    "term", [], Arg_two (fun w h o ->
         let w = int_of_string w in
         let h = int_of_string h in
         o.conn_width <- w;
@@ -2876,7 +2865,7 @@
         "set"),
     "<width> <height> :\t\t\tset terminal width and height (devel)";
 
-    "stdout", Arg_one (fun arg o ->
+    "stdout", [], Arg_one (fun arg o ->
         let b = bool_of_string arg in
         set_logging b;
 	if b then
@@ -2900,7 +2889,7 @@
         (if b then _s "enabled" else _s "disabled")
     ), "<true|false> :\t\t\treactivate log to stdout";
 
-    "debug_client", Arg_multiple (fun args o ->
+    "debug_client", [], Arg_multiple (fun args o ->
         List.iter (fun arg ->
             let num = int_of_string arg in
             debug_clients := Intset.add num !debug_clients;
@@ -2909,7 +2898,7 @@
         _s "done"
     ), "<client nums> :\t\tdebug message in communications with these clients";
 
-    "debug_file", Arg_multiple (fun args o ->
+    "debug_file", [], Arg_multiple (fun args o ->
         List.iter (fun arg ->
             let num = int_of_string arg in
             let file = file_find num in
@@ -2920,7 +2909,7 @@
         _s "done"
     ), "<client nums> :\t\tdebug file state";
 
-    "clear_debug", Arg_none (fun o ->
+    "clear_debug", [], Arg_none (fun o ->
 
         Intset.iter (fun num ->
             try let c = client_find num in
@@ -2930,14 +2919,14 @@
         _s "done"
     ), ":\t\t\t\tclear the table of clients being debugged";
 
-    "merge", Arg_two (fun f1 f2 o ->
+    "merge", [Cmd_download], Arg_two (fun f1 f2 o ->
         let file1 = file_find (int_of_string f1) in
         let file2 = file_find (int_of_string f2) in
         CommonSwarming.merge file1 file2;
         "The two files are now merged"
     ), "<num1> <num2> :\t\t\ttry to swarm downloads from file <num2> (secondary) to file <num1> (primary)";
 
-    "open_log", Arg_none (fun o ->
+    "open_log", [], Arg_none (fun o ->
         if !!log_file <> "" then
 	  begin
 	    let log = !!log_file in
@@ -2948,13 +2937,13 @@
           Printf.sprintf "works only if log_file is set"
     ), ":\t\t\t\tenable logging to file";
 
-    "close_log", Arg_none (fun o ->
+    "close_log", [], Arg_none (fun o ->
   lprintf_nl "Stopped logging...";
         close_log ();
         _s "log stopped"
     ), ":\t\t\t\tclose logging to file";
 
-     "clear_log", Arg_none (fun o ->
+     "clear_log", [], Arg_none (fun o ->
         if !!log_file <> "" then
           begin
             close_log ();
@@ -2967,7 +2956,7 @@
           Printf.sprintf "works only if log_file is set"
      ), ":\t\t\t\tclear log_file";
 
-    "html_mods", Arg_none (fun o ->
+    "html_mods", [], Arg_none (fun o ->
         if !!html_mods then
           begin
             html_mods =:= false;
@@ -2986,7 +2975,7 @@
     ), ":\t\t\t\ttoggle html_mods";
 
 
-    "html_mods_style", Arg_multiple (fun args o ->
+    "html_mods_style", [], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         if args = [] then begin
             Array.iteri (fun i style ->
@@ -3010,7 +2999,7 @@
 
     ), ":\t\t\tselect html_mods_style <#>";
 
-    "rss", Arg_none (fun o ->
+    "rss", [Cmd_download], Arg_none (fun o ->
         let buf = o.conn_buf in
         let module CW = CommonWeb in
         Hashtbl.iter (fun url feed ->
@@ -3070,7 +3059,7 @@
 
     ), ":\t\t\t\t\tprint RSS feeds";
 
-    "html_theme", Arg_multiple (fun args o ->
+    "html_theme", [], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         if args = [] then begin
             Printf.bprintf buf "Usage: html_theme <theme name>\n";
@@ -3095,24 +3084,24 @@
 
     ), "<theme> :\t\t\tselect html_theme";
 
-    "mem_stats", Arg_one (fun level o ->
+    "mem_stats", [], Arg_one (fun level o ->
         let buf = o.conn_buf in
         Heap.print_memstats (int_of_string level) buf (use_html_mods o);
         ""
     ), ":\t\t\t\tprint memory stats";
 
-    "close_all_sockets", Arg_none (fun o ->
+    "close_all_sockets", [], Arg_none (fun o ->
         BasicSocket.close_all ();
         _s "All sockets closed"
     ), ":\t\t\tclose all opened sockets";
 
-    "use_poll", Arg_one (fun arg o ->
+    "use_poll", [], Arg_one (fun arg o ->
         let b = bool_of_string arg in
         BasicSocket.use_poll b;
         Printf.sprintf "poll: %s" (string_of_bool b)
     ), "<bool> :\t\t\tuse poll instead of select";
 
-    "close_fds", Arg_none (fun o ->
+    "close_fds", [], Arg_none (fun o ->
         Unix32.close_all ();
         let buf = o.conn_buf in
         if o.conn_output = HTML then
@@ -3123,12 +3112,12 @@
         ""
     ), ":\t\t\t\tclose all files (use to free space on disk after remove)";
 
-    "debug_socks", Arg_none (fun o ->
+    "debug_socks", [], Arg_none (fun o ->
         BasicSocket.print_sockets o.conn_buf;
         _s "done"
     ), ":\t\t\t\tfor debugging only";
 
-    "block_list", Arg_none (fun o ->
+    "block_list", [Cmd_stat;Cmd_download], Arg_none (fun o ->
       let buf = o.conn_buf in
       if o.conn_output = HTML then
 	List.iter (fun (tablename, l) ->
@@ -3178,7 +3167,7 @@
       _s ""
     ), ":\t\t\t\tdisplay the list of blocked IP ranges that were hit";
 
-    "block_test", Arg_one (fun arg o ->
+    "block_test", [Cmd_download], Arg_one (fun arg o ->
       let ip = Ip.of_string arg in
       _s (match !Ip.banned ip with
           None -> "Not blocked"
diff -a -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/daemon/driver/driverCommands.mli ./src/daemon/driver/driverCommands.mli
--- ./src/daemon/driver/driverCommands.mli	2004-02-04 19:58:17.000000000 +0100
+++ ./src/daemon/driver/driverCommands.mli	2006-05-24 17:37:42.000000000 +0200
@@ -21,6 +21,6 @@
 
 (* val commands : (string * arg_kind * string) list *)
 val execute_command :
-    (string * 'a * arg_kind * string) list ->
+    (string * 'a * cmd_type list * arg_kind * string) list ->
   CommonTypes.ui_conn -> string -> 
   string list -> unit
diff -a -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/daemon/driver/driverControlers.ml ./src/daemon/driver/driverControlers.ml
--- ./src/daemon/driver/driverControlers.ml	2006-05-20 01:43:54.000000000 +0200
+++ ./src/daemon/driver/driverControlers.ml	2006-05-24 17:37:42.000000000 +0200
@@ -124,7 +124,7 @@
             ("", "srh", ""); ];
           Buffer.add_string buf "\\</tr\\>";
           html_mods_cntr_init ();
-          List.iter (fun (cmd, _, _, help) ->
+          List.iter (fun (cmd, _, _, _, help) ->
               let ncmd = ref cmd in
               let nhelp = ref help in
               Printf.bprintf buf "\\<tr class=\\\"dl-%d\\\"\\>" (html_mods_cntr ());
@@ -136,7 +136,7 @@
                   "\\\"\\>wiki\\</a\\>"); ];
               Printf.bprintf buf "\\</tr\\>\n";
           )
-          (List.sort (fun (c1,_, _,_) (c2,_, _,_) -> compare c1 c2)
+          (List.sort (fun (c1,_,_,_,_) (c2,_,_,_,_) -> compare c1 c2)
             !CommonNetwork.network_commands);
           Printf.bprintf buf "\\</table\\>\\</div\\>";
           html_mods_table_header buf "helpTable" "results" [];
@@ -286,7 +286,7 @@
             ";
     | "?" :: args | "help" :: args ->
           List.iter (fun arg ->
-              List.iter (fun (cmd, _, _, help) ->
+              List.iter (fun (cmd, _, _, _, help) ->
                   if cmd = arg then
                     Printf.bprintf  buf "%s %s\n" cmd help)
               !CommonNetwork.network_commands)
diff -a -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/networks/bittorrent/bTInteractive.ml ./src/networks/bittorrent/bTInteractive.ml
--- ./src/networks/bittorrent/bTInteractive.ml	2006-05-20 01:43:54.000000000 +0200
+++ ./src/networks/bittorrent/bTInteractive.ml	2006-05-24 19:03:38.000000000 +0200
@@ -853,7 +853,7 @@
 let commands =
 
     [
-    "compute_torrent", "Network/Bittorrent", Arg_multiple (fun args o ->
+    "compute_torrent", "Network/Bittorrent", [Cmd_download], Arg_multiple (fun args o ->
       let buf = o.conn_buf in
       try
         let filename = ref "" in
@@ -880,7 +880,7 @@
       ""
     ), _s "<filename> <comment> :\tgenerate the corresponding <filename> .torrent file with <comment> in torrents/tracked/.\n\t\t\t\t\tThe file is automatically tracked, and seeded if in incoming/";
 
-    "torrents", "Network/Bittorrent", Arg_none (fun o ->
+    "torrents", "Network/Bittorrent", [Cmd_download;Cmd_upload], Arg_none (fun o ->
       let buf = o.conn_buf in
       if !!BTTracker.tracker_port <> 0 then begin
           Printf.bprintf o.conn_buf (_b ".torrent files available:\n");
@@ -914,7 +914,7 @@
         _s ""
     ), _s ":\t\t\t\tprint all .torrent files on this server";
 
-    "seeded_torrents", "Network/Bittorrent", Arg_none (fun o ->
+    "seeded_torrents", "Network/Bittorrent", [Cmd_upload], Arg_none (fun o ->
       List.iter (fun file ->
           if file_state file = FileShared then
               Printf.bprintf o.conn_buf "%s [%s]\n" file.file_name (Int64.to_string file.file_uploaded)
@@ -923,12 +923,12 @@
 
     ), _s ":\t\t\tprint all seeded .torrent files on this server";
 
-    "reshare_torrents", "Network/Bittorrent", Arg_none (fun o ->
+    "reshare_torrents", "Network/Bittorrent", [Cmd_upload], Arg_none (fun o ->
       share_files ();
       _s "done"
     ), _s ":\t\t\trecheck torrents/* directories for changes";
 
-    "rm_old_torrents", "Network/Bittorrent", Arg_none (fun o ->
+    "rm_old_torrents", "Network/Bittorrent", [], Arg_none (fun o ->
       let files_outdated = Unix2.list_directory old_directory in
       let buf = o.conn_buf in
       if o.conn_output = HTML then begin
@@ -952,7 +952,7 @@
       _s ""
     ), _s ":\t\t\tremove all old .torrent files";
 
-    "startbt", "Network/Bittorrent", Arg_one (fun url o ->
+    "startbt", "Network/Bittorrent", [Cmd_download], Arg_one (fun url o ->
       let buf = o.conn_buf in
       if Sys.file_exists url then
         begin
@@ -968,7 +968,7 @@
       _s ""
      ),  "<url>:\t [<URL|file>] start BT download";
 
-    "stop_all_bt", "Network/Bittorrent", Arg_none (fun o ->
+    "stop_all_bt", "Network/Bittorrent", [Cmd_download], Arg_none (fun o ->
       List.iter (fun file -> BTClients.file_stop file ) !current_files;
       let buf = o.conn_buf in
       if o.conn_output = HTML then
@@ -979,7 +979,7 @@
        _s ""
     ), _s ":\t\t\t\tstops all bittorrent downloads, use this if you want to make sure that the stop signal actualy gets to the tracker\n\t\t\t\t\twhen shuting mlnet down, but you have to wait till the stops get to the tracker and not wait too long,\n\t\t\t\t\tso mldonkey reconnects to the tracker :)";
 
-    "tracker", "Network/Bittorrent", Arg_multiple (fun args o ->
+    "tracker", "Network/Bittorrent", [Cmd_download], Arg_multiple (fun args o ->
         try
           let num = ref "" in
           let urls = ref [] in
diff -a -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/networks/bittorrent/bTStats.ml ./src/networks/bittorrent/bTStats.ml
--- ./src/networks/bittorrent/bTStats.ml	2006-01-26 11:34:53.000000000 +0100
+++ ./src/networks/bittorrent/bTStats.ml	2006-05-24 19:03:50.000000000 +0200
@@ -95,12 +95,12 @@
 
   register_commands
     [
-    "client_stats_bt", "Network/Bittorrent",Arg_none (fun o ->
+    "client_stats_bt", "Network/Bittorrent", [Cmd_stat], Arg_none (fun o ->
         print_stats o Old;
         ""
     ), ":\t\t\tshow breakdown of download/upload by clients brand";
 
-    "csbt", "Network/Bittorrent",Arg_none (fun o ->
+    "csbt", "Network/Bittorrent", [Cmd_stat], Arg_none (fun o ->
         print_stats o New;
         ""
     ), ":\t\t\t\t\tshow table of download/upload by BT clients brand";
diff -a -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/networks/donkey/donkeyInteractive.ml ./src/networks/donkey/donkeyInteractive.ml
--- ./src/networks/donkey/donkeyInteractive.ml	2006-05-20 01:43:54.000000000 +0200
+++ ./src/networks/donkey/donkeyInteractive.ml	2006-05-24 18:59:49.000000000 +0200
@@ -602,10 +602,10 @@
 
 let register_commands list =
   register_commands
-    (List2.tail_map (fun (n,f,h) -> (n, "Network/Edonkey", f,h)) list)
+    (List2.tail_map (fun (n,t,f,h) -> (n,"Network/Edonkey",t,f,h)) list)
 
 let commands = [
-    "n", Arg_multiple (fun args o ->
+    "n", [Cmd_server], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
         let ip, port =
           match args with
@@ -622,7 +622,7 @@
         ""
     ), "<ip> [<port>] :\t\t\tadd a server";
 
-    "afr", Arg_multiple (fun args o ->
+    "afr", [Cmd_server], Arg_multiple (fun args o ->
         let ip, port =
           match args with
             [ip ; port] -> ip, port
@@ -636,7 +636,7 @@
         "friend added";
     ),  "<ip> [<port>] :\t\t\tadd a friend";
 
-    "vu", Arg_none (fun o ->
+    "vu", [], Arg_none (fun o ->
         Printf.sprintf
           "Upload credits : %d minutes\nUpload disabled for %d minutes"
           !CommonUploads.upload_credit !CommonUploads.has_upload;
@@ -650,7 +650,7 @@
         "comments loaded and saved"
     ), "<filename> :\t\t\tload comments from file";
 
-    "comment", Arg_two (fun md4 comment o ->
+    "comment", [], Arg_two (fun md4 comment o ->
         let buf = o.conn_buf in
         let md4 = Md4.of_string md4 in
 (* TODO        DonkeyIndexer.add_comment md4 comment; *)
@@ -658,7 +658,7 @@
     ), "<md4> \"<comment>\" :\t\tadd comment on a md4";
 *)
 
-    "import", Arg_one (fun dirname o ->
+    "import", [], Arg_one (fun dirname o ->
         try
           import_config dirname;
           "config loaded"
@@ -667,7 +667,7 @@
               Printexc2.to_string e)
     ), "<dirname> :\t\t\timport the config from dirname";
 
-    "import_temp", Arg_one (fun dirname o ->
+    "import_temp", [Cmd_download], Arg_one (fun dirname o ->
         try
           import_temp dirname;
           "temp files loaded"
@@ -676,14 +676,7 @@
               Printexc2.to_string e)
     ), "<temp_dir> :\t\timport the old edonkey temp directory";
 
-(*
-    "load_old_history", Arg_none (fun o ->
-(* TODO        DonkeyIndexer.load_old_history (); *)
-        "Old history loaded"
-    ), ":\t\t\tload history.dat file";
-*)
-
-    "servers", Arg_one (fun filename o ->
+    "servers", [Cmd_server], Arg_one (fun filename o ->
   if !!update_server_list_server_met then
     begin
       let nservers = List.length (Hashtbl2.to_list servers_by_key) in
@@ -705,7 +698,7 @@
     Printf.sprintf "ED2K_update_server_list_met is disabled, ignoring..."
     ), "<filename|URL> :\t\tadd the servers from a server.met file or URL";
 
-    "id", Arg_none (fun o ->
+    "id", [Cmd_server], Arg_none (fun o ->
         let buf = o.conn_buf in
         List.iter (fun s ->
             Printf.bprintf buf "For %s:%d  --->   %s\n"
@@ -721,7 +714,7 @@
         ""
     ), ":\t\t\t\t\tprint ID on connected servers";
 
-    "recover_bytes", Arg_multiple (fun args o ->
+    "recover_bytes", [Cmd_download], Arg_multiple (fun args o ->
         let buf = o.conn_buf in
 
         List.iter (fun arg ->
@@ -745,7 +738,7 @@
         ""
     ) , "<f1> < f2> ... :\t\ttry to recover these files at byte level";
 
-    "preferred", Arg_two (fun arg1 arg2 o ->
+    "preferred", [Cmd_server], Arg_two (fun arg1 arg2 o ->
         let preferred = bool_of_string arg1 in
         let ip = Ip.of_string arg2 in
         Hashtbl.iter (fun ip_s s ->
@@ -757,7 +750,7 @@
         "ok"
     ), "<true/false> <ip> :\t\tset the server with this IP as preferred";
 
-    "bs", Arg_multiple (fun args o ->
+    "bs", [Cmd_server], Arg_multiple (fun args o ->
         List.iter (fun arg ->
             let ip = Ip.of_string arg in
             server_black_list =:=  ip :: !!server_black_list;
@@ -765,12 +758,12 @@
         "done"
     ), "<ip1> <ip2> ... :\t\t\tadd these IPs to the servers black list";
 
-    "port", Arg_one (fun arg o ->
+    "port", [], Arg_one (fun arg o ->
         donkey_port =:= int_of_string arg;
         "new port will change at next restart"),
     "<port> :\t\t\t\tchange connection port";
 
-    "scan_temp", Arg_none (fun o ->
+    "scan_temp", [], Arg_none (fun o ->
         let buf = o.conn_buf in
         let list = Unix2.list_directory !!temp_directory in
 
@@ -872,21 +865,13 @@
         ""
     ), ":\t\t\t\tprint temp directory content";
 
-    "sources", Arg_none (fun o ->
+    "sources", [Cmd_download], Arg_none (fun o ->
         let buf = o.conn_buf in
         DonkeySources.print buf o.conn_output;
         ""
     ), ":\t\t\t\tshow sources currently known";
 
-    (*
-    "update_sources", Arg_none (fun o ->
-        let buf = o.conn_buf in
-        DonkeySources.recompute_ready_sources ();
-        "done"
-    ), ":\t\t\trecompute order of connections to sources (experimental)";
-*)
-
-    "xs", Arg_none (fun o ->
+    "xs", [Cmd_download], Arg_none (fun o ->
         let buf = o.conn_buf in
         if !xs_last_search >= 0 then begin
             try
@@ -907,20 +892,20 @@
         ""
     ), ":\t\t\t\t\textend the last search";
 
-    "clh", Arg_none (fun o ->
+    "clh", [Cmd_download], Arg_none (fun o ->
 (* TODO RESULT        DonkeyIndexer.clear (); *)
         "local history cleared"
     ), ":\t\t\t\t\tclear local history";
 
 (* TODO RESULT *)
-    "dd", Arg_two(fun size md4 o ->
+    "dd", [Cmd_download], Arg_two (fun size md4 o ->
         let file = query_download [] (Int64.of_string size)
           (Md4.of_string md4) None None None false in
         CommonInteractive.start_download file;
         "download started"
     ), "<size> <md4> :\t\t\tdownload from size and md4";
 
-    "remove_old_servers", Arg_none (fun o ->
+    "remove_old_servers", [Cmd_server], Arg_none (fun o ->
         let buf = o.conn_buf in
         DonkeyServers.remove_old_servers ();
         if o.conn_output = HTML then
@@ -931,13 +916,13 @@
         ""
     ), ":\t\t\tremove servers that have not been connected for several days";
 
-    "reset_md4", Arg_none (fun _ ->
+    "reset_md4", [], Arg_none (fun _ ->
         set_simple_option donkey_ini "client_md4" (Md4.to_string (mldonkey_md4 (Md4.random ())));
         if Autoconf.donkey_sui_works () then set_simple_option donkey_ini "client_private_key" (DonkeySui.SUI.create_key ());
         "reset client_md4/client_private_key"
     ), ":\t\t\t\treset client_md4/client_private_key to random values";
 
-    "bp", Arg_multiple (fun args o ->
+    "bp", [], Arg_multiple (fun args o ->
         List.iter (fun arg ->
             let port = int_of_string arg in
             port_black_list =:=  port :: !!port_black_list;
diff -a -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/networks/donkey/donkeyOvernet.ml ./src/networks/donkey/donkeyOvernet.ml
--- ./src/networks/donkey/donkeyOvernet.ml	2006-05-20 01:43:54.000000000 +0200
+++ ./src/networks/donkey/donkeyOvernet.ml	2006-05-24 19:01:44.000000000 +0200
@@ -1556,14 +1556,14 @@
 
 let register_commands list =
   register_commands
-    (List2.tail_map (fun (n,f,h) -> (n, "Network/Overnet", f,h)) list)
+    (List2.tail_map (fun (n,t,f,h) -> (n,"Network/Overnet",t,f,h)) list)
 
 let _ =
   register_commands
-    (List.map (fun (command, args, help) ->
-        command_prefix ^ command, args, help)
+    (List.map (fun (command, cmd_type, args, help) ->
+        command_prefix ^ command, cmd_type, args, help)
     [
-    "dump_bucket", Arg_one (fun i o ->
+    "dump_bucket", [Cmd_stat], Arg_one (fun i o ->
          let i = int_of_string i in
          let i = min i !n_used_buckets in
          let buf = o.conn_buf in
@@ -1587,7 +1587,7 @@
          ""
     ), ("<bucket_nr> :\t\tdumps a bucket");
 
-    "dump_known_peers", Arg_none (fun o ->
+    "dump_known_peers", [Cmd_stat], Arg_none (fun o ->
          let buf = o.conn_buf in
 
          Printf.bprintf buf "Peers of known_peers:\n";
@@ -1598,21 +1598,21 @@
          ""
     ), (":\t\t\tdumps known_peers");
 
-    "boot", Arg_two (fun ip port o ->
+    "boot", [Cmd_server], Arg_two (fun ip port o ->
         let ip = Ip.from_name ip in
         let port = int_of_string port in
         bootstrap ip port;
         Printf.sprintf "peer %s:%d added" (Ip.to_string ip) port
     ), ("<ip> <port> :\t\t\tadd an " ^ command_prefix_to_net ^ " peer");
 
-    "link", Arg_multiple (fun args o ->
+    "link", [Cmd_download], Arg_multiple (fun args o ->
         let url = String2.unsplit args ' ' in
         if parse_overnet_url url then
           "download started"
         else "bad syntax"
     ), "<fhalink> :\t\t\tdownload fha:// link";
 
-    "view_stats_cmds", Arg_none (fun o ->
+    "view_stats_cmds", [Cmd_stat], Arg_none (fun o ->
         let buf = o.conn_buf in
         html_mods_commands buf "commandsTable" "commands" ([
           ("bu bbig", command_prefix_to_net ^ " boots list",
@@ -1631,7 +1631,7 @@
         "";
     ), (":\t\t\t" ^ command_prefix_to_net ^ " Stats commands");
 
-    "stats", Arg_none (fun o ->
+    "stats", [Cmd_stat], Arg_none (fun o ->
         let buf = o.conn_buf in
         if o.conn_output = HTML then
           begin
@@ -1706,7 +1706,7 @@
         "";
     ), ":\t\t\t\t" ^ command_prefix_to_net ^ " Stats";
 
-    "web", Arg_multiple (fun args o ->
+    "web", [Cmd_server], Arg_multiple (fun args o ->
         let urls =
           match args with
             [] -> let list = ref [] in
@@ -1722,7 +1722,7 @@
         "web boot started"
     ), "<urls> : \t\t\tdownload .ocl URLs (no arg load default)";
 
-    "load", Arg_one (fun filename o ->
+    "load", [Cmd_server], Arg_one (fun filename o ->
         try
           let n = load_contact_dat filename in
           Printf.sprintf "%d overnet peers loaded" n;
@@ -1730,10 +1730,10 @@
             Printf.sprintf "error %s while loading file" (Printexc2.to_string e)
     ), "<filename> :\t\t\tload the peers from a contact.dat file";
 
-    "md4", Arg_none (fun o -> "MD4 is " ^ (Md4.to_string !!overnet_md4);
+    "md4", [], Arg_none (fun o -> "MD4 is " ^ (Md4.to_string !!overnet_md4);
     ), ":\t\t\t\tget client MD4 address on the Overnet/Kademlia network";
 
-    "store", Arg_none (fun o ->
+    "store", [Cmd_stat], Arg_none (fun o ->
         let buf = o.conn_buf in
         if o.conn_output = HTML then
           begin
@@ -1766,7 +1766,7 @@
         ""
     ), ":\t\t\t\tdump the " ^ command_prefix_to_net ^ " File Store";
 
-    "send_udp", Arg_three (fun ip port hex o ->
+    "send_udp", [], Arg_three (fun ip port hex o ->
         try
           let rec hex_to_msg h =
             match h with
@@ -1786,7 +1786,7 @@
             lprintf_nl "Unable to send UDP message"; "Unable to send UDP message"
     ), ":\t\t\t\tsend UDP message (<ip> <port> <msg in hex>)";
     
-    "buckets", Arg_none (fun o ->
+    "buckets", [Cmd_stat], Arg_none (fun o ->
         let buf = o.conn_buf in
         update_buckets ();
         if o.conn_output = HTML then
@@ -1815,7 +1815,7 @@
           ""
     ), ":\t\t\t\tprint buckets table status";
 
-    "boots", Arg_none (fun o ->
+    "boots", [Cmd_stat], Arg_none (fun o ->
         let buf = o.conn_buf in
         LimitedList.iter (fun (ip, port) ->
             Printf.bprintf buf "   %s:%d\n" (Ip.to_string ip) port;
diff -a -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/networks/donkey/donkeyReliability.ml ./src/networks/donkey/donkeyReliability.ml
--- ./src/networks/donkey/donkeyReliability.ml	2005-08-08 18:47:31.000000000 +0200
+++ ./src/networks/donkey/donkeyReliability.ml	2006-05-24 17:37:42.000000000 +0200
@@ -213,7 +213,7 @@
 let _ =
   register_commands
     [
-      "dump_reliability", "Network/Donkey", Arg_none (fun o ->
+      "dump_reliability", "Network/Donkey", [], Arg_none (fun o ->
 	let buf = o.conn_buf in
 	bprint_reliability_table buf;
 	""
diff -a -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/networks/donkey/donkeyStats.ml ./src/networks/donkey/donkeyStats.ml
--- ./src/networks/donkey/donkeyStats.ml	2006-01-26 11:34:53.000000000 +0100
+++ ./src/networks/donkey/donkeyStats.ml	2006-05-24 19:02:15.000000000 +0200
@@ -172,21 +172,21 @@
 
   register_commands
     [
-    "client_stats", "Network/Donkey",Arg_none (fun o ->
+    "client_stats", "Network/Donkey", [Cmd_stat], Arg_none (fun o ->
         print_stats o Old false;
         ""
     ), ":\t\t\t\tshow breakdown of download/upload by clients brand";
 
-    "cs", "Network/Donkey",Arg_none (fun o ->
+    "cs", "Network/Donkey", [Cmd_stat], Arg_none (fun o ->
         print_stats o New false;
         ""
     ), ":\t\t\t\t\tshow table of download/upload by ED2K clients brand";
 
-    "csm", "Network/Donkey",Arg_none (fun o ->
+    "csm", "Network/Donkey", [Cmd_stat], Arg_none (fun o ->
         print_stats o New true;
         ""
     ), ":\t\t\t\t\tshow table of download/upload by eMule MODs";
-    "reset_stats", "Network/Donkey",Arg_none (fun o ->
+    "reset_stats", "Network/Donkey", [], Arg_none (fun o ->
 
        Array.iteri  (fun x _ ->
          stats_array.(x).brand_seen <- 0;
diff -a -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/networks/fileTP/fileTPInteractive.ml ./src/networks/fileTP/fileTPInteractive.ml
--- ./src/networks/fileTP/fileTPInteractive.ml	2006-05-20 01:43:54.000000000 +0200
+++ ./src/networks/fileTP/fileTPInteractive.ml	2006-05-24 18:50:09.000000000 +0200
@@ -295,7 +295,7 @@
 open GuiTypes
 
 let commands = [
-    "http", "Network/FileTP", Arg_multiple (fun args o ->
+    "http", "Network/FileTP", [Cmd_download], Arg_multiple (fun args o  ->
         try
         (match args with
           url :: [referer] -> download_file url referer
@@ -327,7 +327,7 @@
             _s ""
     ), "<url> <referer> :\t\t\tstart downloading this URL";
 
-    "mirror", "Network/FileTP", Arg_multiple (fun args o ->
+    "mirror", "Network/FileTP", [Cmd_download], Arg_multiple (fun args o  ->
         try
           let num = ref "" in
           let url = ref "" in
diff -a -x CVS -x Root -x Repository -x Tag -x Entries -x Entries.Log -x .svn -x '*.rej' -x '*.orig' -x .cvsignore -N -r -u ./src/networks/gnutella/gnutellaInteractive.ml ./src/networks/gnutella/gnutellaInteractive.ml
--- ./src/networks/gnutella/gnutellaInteractive.ml	2006-05-20 01:43:55.000000000 +0200
+++ ./src/networks/gnutella/gnutellaInteractive.ml	2006-05-24 18:49:55.000000000 +0200
@@ -503,7 +503,7 @@
 open GuiTypes
   
 let commands = [
-    "gstats", "Network/Gnutella", Arg_none (fun o ->
+    "gstats", "Network/Gnutella", [Cmd_stat], Arg_none (fun o ->
         let buf = o.conn_buf in
         if o.conn_output = HTML then
           begin
