diff -rup 1-initial-patches/ejabberd-2.0.0-beta1/src/mod_register.erl 2-big-patch/ejabberd-2.0.0-beta1/src/mod_register.erl
--- 1-initial-patches/ejabberd-2.0.0-beta1/src/mod_register.erl	2008-08-22 13:07:54.000000000 +0200
+++ 2-big-patch/ejabberd-2.0.0-beta1/src/mod_register.erl	2008-08-22 13:06:54.000000000 +0200
@@ -192,8 +192,6 @@ try_register(User, Server, Password) ->
 		allow ->
 		    case ejabberd_auth:try_register(User, Server, Password) of
 			{atomic, ok} ->
-			    ejabberd_hooks:run(user_registered, Server,
-					       [User, Server]),
 			    send_welcome_message(JID),
 			    send_registration_notifications(JID),
 			    ok;
Seulement dans 1-initial-patches/ejabberd-2.0.0-beta1/src: mod_register.erl.orig
diff -rup 1-initial-patches/ejabberd-2.0.0-beta1/src/mod_shared_roster.erl 2-big-patch/ejabberd-2.0.0-beta1/src/mod_shared_roster.erl
--- 1-initial-patches/ejabberd-2.0.0-beta1/src/mod_shared_roster.erl	2008-08-22 13:08:04.000000000 +0200
+++ 2-big-patch/ejabberd-2.0.0-beta1/src/mod_shared_roster.erl	2008-08-22 13:08:18.000000000 +0200
@@ -46,7 +46,7 @@
 	 delete_group/2,
 	 get_group_opts/2,
 	 set_group_opts/3,
-	 get_group_users/2,
+	 get_group_users/3,
 	 get_group_explicit_users/2,
 	 add_user_to_group/3,
 	 remove_user_from_group/3]).
@@ -135,7 +135,7 @@ get_user_roster(Items, US) ->
 						   get_group_name(S, Group),
 						   Acc2)
 			    end
-		    end, Acc1, get_group_users(S, Group))
+		    end, Acc1, get_group_users(U, S, Group))
 	  end, dict:new(), DisplayedGroups),
 
     %% If partially subscribed users are also in shared roster, show them as
@@ -196,7 +196,7 @@ get_subscription_lists({F, T}, User, Ser
 	lists:usort(
 	  lists:flatmap(
 	    fun(Group) ->
-		    get_group_users(LServer, Group)
+		    get_group_users(LUser, LServer, Group)
 	    end, DisplayedGroups)),
     SRJIDs = [{U1, S1, ""} || {U1, S1} <- SRUsers],
     {lists:usort(SRJIDs ++ F), lists:usort(SRJIDs ++ T)}.
@@ -215,7 +215,7 @@ get_jid_info({Subscription, Groups}, Use
 		    fun(User1, Acc2) ->
 			    dict:append(
 			      User1, get_group_name(LServer, Group), Acc2)
-		    end, Acc1, get_group_users(LServer, Group))
+		    end, Acc1, get_group_users(LUser, LServer, Group))
 	  end, dict:new(), DisplayedGroups),
     case dict:find(US1, SRUsers) of
 	{ok, GroupNames} ->
@@ -245,7 +245,7 @@ process_subscription(Direction, User, Se
 	lists:usort(
 	  lists:flatmap(
 	    fun(Group) ->
-		    get_group_users(LServer, Group)
+		    get_group_users(LUser, LServer, Group)
 	    end, DisplayedGroups)),
     case lists:member(US1, SRUsers) of
 	true ->
@@ -267,6 +267,13 @@ list_groups(Host) ->
 	[{'==', '$2', Host}],
 	['$1']}]).
 
+groups_with_opts(Host) ->
+    lists:map(fun([G,O]) -> {G, O} end,
+	mnesia:dirty_select(sr_group,
+	    [{#sr_group{group_host={'$1', Host}, opts='$2', _='_'},
+	    [],
+	    [['$1','$2']] }])).
+
 create_group(Host, Group) ->
     create_group(Host, Group, []).
 
@@ -336,52 +343,50 @@ get_group_opt(Host, Group, Opt, Default)
     end.
 
 -record(last_activity, {us, timestamp, status}).
+-record(session, {sid, usr, us, priority, info}).
 
-%% stolen from mod_ctlextra, thanks Badlop! :)
 get_recent_users(Host, Days) ->
+    LServer = jlib:nameprep(Host),
     %% Convert older time
     SecOlder = Days*24*60*60,
 
     %% Get current time
     {MegaSecs, Secs, _MicroSecs} = now(),
-    TimeStamp_now = MegaSecs * 1000000 + Secs,
-
-    %% Get the list of registered users
-    Users = ejabberd_auth:get_vh_registered_users(Host),
+    TimeStampOlder = MegaSecs * 1000000 + Secs - SecOlder,
 
-    %% For a user, answer true if they are online, or were online within
-    %% the given number of Days
-    F = fun({LUser, LServer}) ->
-		%% Check if the user is logged
-		case ejabberd_sm:get_user_resources(LUser, LServer) of
-		    %% If it isnt
-		    [] ->
-			%% Look for his last_activity
-			case mnesia:dirty_read(last_activity, {LUser, LServer}) of
-			    %% If it is existent:
-			    [#last_activity{timestamp = TimeStamp}] ->
-				%% get his age
-				Sec = TimeStamp_now - TimeStamp,
-				%% true if he's recently active
-				Sec < SecOlder;
-			    %% nonexistent:
-			    [] ->
-				%% never signed in, skip
-				false
-			end;
-		    %% Else
-		    _ ->
-			%% currently online, include
-			true
-		end
-	end,
-    %% Apply the function to every user in the list
-    lists:filter(F, Users).
+    %% Get the list of recently connected users
+    RecentUsers = mnesia:dirty_select(last_activity, 
+        [{#last_activity{us={'$1',LServer},timestamp='$2',_='_'},
+          [{'>','$2',TimeStampOlder}],
+          ['$1'] }]),
+    %% Get the list of connected users
+    OnlineUsers = mnesia:dirty_select(session, 
+        [{#session{us={'$1',LServer}, _='_'}, 
+         [], 
+         ['$1']}]),
+    
+    Users = lists:usort(RecentUsers++OnlineUsers),
+    lists:map(fun(User) -> {User, LServer} end, Users).
 
 get_online_users(Host) ->
     lists:usort([{U, S} || {U, S, _} <- ejabberd_sm:get_vh_session_list(Host)]).
 
-get_group_users(Host, Group) ->
+get_nearby_users(User, Host) ->
+    Resources = ejabberd_sm:get_user_resources(User, Host),
+    Sessions = ejabberd_sm:get_vh_session_list(Host),
+    Nearby = lists:foldl(
+      fun(Resource, Acc1) ->
+        lists:foldl(
+          fun({U, S, R}, Acc2) ->
+            if
+              R == Resource -> {U, S} ++ Acc2;
+              true -> Acc2
+            end
+          end, [], Sessions) ++ Acc1
+      end, [], Resources),
+    lists:usort(Nearby).
+
+get_group_users(User, Host, Group) ->
     case get_group_opt(Host, Group, all_users, false) of
 	true ->
 	    ejabberd_auth:get_vh_registered_users(Host);
@@ -400,6 +405,39 @@ get_group_users(Host, Group) ->
 	false ->
 	    []
     end ++
+    case get_group_opt(Host, Group, nearby_users, false) of
+	true ->
+	    get_nearby_users(User, Host);
+	false ->
+	    []
+    end ++
+    get_group_explicit_users(Host, Group).
+    
+get_group_users(User, Host, Group, GroupOpts) ->
+    case proplists:get_value(all_users, GroupOpts, false) of
+	true ->
+	    ejabberd_auth:get_vh_registered_users(Host);
+	false ->
+	    []
+    end ++
+    case proplists:get_value(recent_users_days, GroupOpts, 0) of
+	0 ->
+	    [];
+	Days when is_integer(Days) ->
+            get_recent_users(Host, Days)
+    end ++
+    case proplists:get_value(online_users, GroupOpts, false) of
+	true ->
+	    get_online_users(Host);
+	false ->
+	    []
+    end ++
+    case proplists:get_value(nearby_users, GroupOpts, false) of
+	true ->
+	    get_nearby_users(User, Host);
+	false ->
+	    []
+    end ++
     get_group_explicit_users(Host, Group).
 
 get_group_explicit_users(Host, Group) ->
@@ -419,9 +457,38 @@ get_special_users_groups(Host) ->
       fun(Group) ->
 	get_group_opt(Host, Group, all_users, false) orelse
 	get_group_opt(Host, Group, recent_users_days, 0) > 0 orelse
-	get_group_opt(Host, Group, online_users, false) end,
+	get_group_opt(Host, Group, online_users, false) orelse
+	get_group_opt(Host, Group, nearby_users, false) end,
       list_groups(Host)).
 
+displayed_groups(GroupsOpts, SelectedGroupsOpts) ->
+    DisplayedGroups = lists:usort(
+	lists:flatmap(
+	    fun({_Group, Opts}) ->
+		[G || G <- proplists:get_value(displayed_groups, Opts, []), not lists:member(disabled, Opts)]
+	    end, SelectedGroupsOpts)),
+    [G || G <- DisplayedGroups, not lists:member(disabled, proplists:get_value(G, GroupsOpts, []))].
+
+get_special_displayed_groups(GroupsOpts) ->
+    Groups = lists:filter(
+	fun({_Group, Opts}) ->
+	    proplists:get_value(all_users, Opts, false) orelse
+	    proplists:get_value(recent_users_days, Opts, 0) > 0 orelse
+	    proplists:get_value(online_users, Opts, false) orelse
+	    proplists:get_value(nearby_users, Opts, false)
+	end, GroupsOpts),
+    displayed_groups(GroupsOpts, Groups).
+
+get_user_displayed_groups(LUser, LServer, GroupsOpts) ->
+    Groups = case catch mnesia:dirty_read(sr_user, {LUser, LServer}) of
+	Rs when is_list(Rs) ->
+	    [{Group, proplists:get_value(Group, GroupsOpts, [])} ||
+		    #sr_user{group_host = {Group, H}} <- Rs, H == LServer];
+	_ ->
+	    []
+    end,
+    displayed_groups(GroupsOpts, Groups).
+
 get_user_displayed_groups(US) ->
     Host = element(2, US),
     DisplayedGroups1 =
@@ -462,24 +529,25 @@ remove_user_from_group(Host, US, Group) 
 user_registered(User, Server) ->
     LUser = jlib:nodeprep(User),
     LServer = jlib:nameprep(Server),
-    US = {LUser, LServer},
-    DisplayedGroups = get_user_displayed_groups(US),
+    GroupsOpts = groups_with_opts(LServer),
+    SpecialGroups = get_special_displayed_groups(GroupsOpts),
+    UserGroups = get_user_displayed_groups(LUser, LServer, GroupsOpts),
     lists:foreach(
       fun(Group) ->
-	      USs = get_group_users(LServer, Group),
-	      lists:foreach(
-		fun({U, S} = US1) ->
-			Item = #roster{usj = {U, S, {LUser, LServer, ""}},
-				       us = US1,
-				       jid = {LUser, LServer, ""},
-				       name = "",
-				       subscription = both,
-				       ask = none,
-				       groups = [get_group_name(
-						   LServer, Group)]},
-			push_item(U, S, jlib:make_jid("", S, ""), Item)
-		end, USs)
-      end, DisplayedGroups).
+	    GroupOpts = proplists:get_value(Group, GroupsOpts, []),
+	    GroupName = proplists:get_value(name, GroupOpts, Group),
+	    lists:foreach(
+	    fun({U, S}) ->
+		    Item = #roster{usj = {U, S, {LUser, LServer, ""}},
+				    us = {U, S},
+				    jid = {LUser, LServer, ""},
+				    name = "",
+				    subscription = both,
+				    ask = none,
+				    groups = [GroupName]},
+		    push_item(U, S, jlib:make_jid("", S, ""), Item)
+	    end, get_group_users(LUser, LServer, Group, GroupOpts))
+      end, lists:usort(SpecialGroups++UserGroups)).
 
 %% get a roster item for a contact from a particular user's
 %% perspective, considering both normal and shared roster items
@@ -501,35 +569,38 @@ get_user_roster_item(FromUS, ToUS) ->
 user_available(New) ->
     LUser = New#jid.luser,
     LServer = New#jid.lserver,
+    Resources = ejabberd_sm:get_user_resources(LUser, LServer),
     ?INFO_MSG("user_available for ~p @ ~p (~p resources)",
-        [LUser, LServer,
-         length(ejabberd_sm:get_user_resources(LUser, LServer))]),
-    case length(ejabberd_sm:get_user_resources(LUser, LServer)) of
+        [LUser, LServer, length(Resources)]),
+    case length(Resources) of
       %% first session for this user
       1 ->
 	%% find all online users on the new user's server, but not the new user himself
-	OnlineUsers = [US || US <- get_online_users(LServer),
-			     US /= {LUser, LServer}],
+	OnlineUsers = lists:usort(
+	    [U || {U, _, _} <- ejabberd_sm:get_vh_session_list(LServer), U /= LUser]),
+	GroupsOpts = groups_with_opts(LServer),
+	SpecialGroups = get_special_displayed_groups(GroupsOpts),
 	%% for each of these people
 	lists:foreach(
-	  fun({U, S} = OnlineUS) ->
+	  fun(OnlineUser) ->
 	    %% see if they are displaying any @online@ groups
-	    DisplayedGroups = get_user_displayed_groups(OnlineUS),
+	    UserGroups = get_user_displayed_groups(OnlineUser, LServer, GroupsOpts),
 	    OnlineGroups = lists:filter(
 		fun(Group) ->
-		  get_group_opt(LServer, Group, online_users, false)
-		end, DisplayedGroups),
+		    GroupOpts = proplists:get_value(Group, GroupsOpts, []),
+		    proplists:get_value(online_users, GroupOpts, false) orelse
+		    proplists:get_value(nearby_users, GroupOpts, false)
+		end, lists:usort(UserGroups++SpecialGroups)),
 	    case OnlineGroups of
-	      [] ->
+	    [] ->
 		ok;
-	      _ ->
+	    _ ->
 		%% if so, push them an item for the new user
-		case get_user_roster_item({LUser, LServer}, OnlineUS) of
-		  Item when is_record(Item, roster) ->
-		    push_item(U, S, jlib:make_jid("", S, ""), Item), ok;
-		  _ ->
-		    ok
-		end
+		Item = case get_user_roster_item({LUser, LServer}, {OnlineUser, LServer}) of
+		I when is_record(I, roster) -> I;
+		_ -> none
+		end,
+		push_item(OnlineUser, LServer, jlib:make_jid("", LServer, ""), Item)
 	    end
 	  end, OnlineUsers);
       _ ->
@@ -537,68 +608,70 @@ user_available(New) ->
     end.
 
 unset_presence(LUser, LServer, Resource, Status) ->
+    Resources = ejabberd_sm:get_user_resources(LUser, LServer),
     ?INFO_MSG("unset_presence for ~p @ ~p / ~p -> ~p (~p resources)",
-        [LUser, LServer, Resource, Status,
-         length(ejabberd_sm:get_user_resources(LUser, LServer))]),
+        [LUser, LServer, Resource, Status, length(Resources)]),
     %% if user has no resources left...
-    case length(ejabberd_sm:get_user_resources(LUser, LServer)) of
+    case length(Resources) of
       0 ->
 	%% find all users on their server
-	OnlineUsers = get_online_users(LServer),
+	OnlineUsers = lists:usort(
+	    [U || {U, _, _} <- ejabberd_sm:get_vh_session_list(LServer)]),
+	GroupsOpts = groups_with_opts(LServer),
+	SpecialGroups = get_special_displayed_groups(GroupsOpts),
+	%% for each of these people
 	lists:foreach(
-	  fun({U, S} = OnlineUS) ->
+	  fun(OnlineUser) ->
 	    %% see if they are displaying any @online@ groups
-	    DisplayedGroups = get_user_displayed_groups(OnlineUS),
+	    UserGroups = get_user_displayed_groups(OnlineUser, LServer, GroupsOpts),
 	    OnlineGroups = lists:filter(
-	      fun(Group) ->
-		get_group_opt(LServer, Group, online_users, false)
-	      end, DisplayedGroups),
+		fun(Group) ->
+		    GroupOpts = proplists:get_value(Group, GroupsOpts, []),
+		    proplists:get_value(online_users, GroupOpts, false) orelse
+		    proplists:get_value(nearby_users, GroupOpts, false)
+		end, lists:usort(UserGroups++SpecialGroups)),
 	    case OnlineGroups of
-	      [] ->
-	        ok;
-	      _ ->
+	    [] ->
+		ok;
+	    _ ->
 		%% push them their item for the departed user, or remove it
-		case get_user_roster_item({LUser, LServer}, OnlineUS) of
-		  Item when is_record(Item, roster) ->
-		    PushItem = Item;
-		  _ ->
-		    PushItem = #roster{usj = {U, S, {LUser, LServer, ""}},
-				       us = OnlineUS,
-				       jid = {LUser, LServer, ""},
-				       name = "",
-				       subscription = remove,
-				       ask = none,
-				       groups = []}
+		Item = case get_user_roster_item({LUser, LServer}, {OnlineUser, LServer}) of
+		I when is_record(I, roster) -> I;
+		_ -> #roster{usj = {OnlineUser, LServer, {LUser, LServer, ""}},
+				us = {OnlineUser, LServer},
+				jid = {LUser, LServer, ""},
+				name = "",
+				subscription = remove,
+				ask = none,
+				groups = []}
 		end,
-		push_item(U, S, jlib:make_jid("", S, ""), PushItem),
-		ok
+		push_item(OnlineUser, LServer, jlib:make_jid("", LServer, ""), Item)
 	    end
 	  end, OnlineUsers);
       _ ->
 	ok
     end.
 
+push_item(_User, _Server, _From, none) -> 
+    ok;
 push_item(User, Server, From, Item) ->
-    ejabberd_sm:route(jlib:make_jid("", "", ""),
-		      jlib:make_jid(User, Server, ""),
+    % was ejabberd_sm:route(jlib:make_jid("", "", ""), jlib:make_jid(User, Server, ""), why ?
+    ejabberd_sm:route(From, jlib:make_jid(User, Server, ""),
 		      {xmlelement, "broadcast", [],
 		       [{item,
 			 Item#roster.jid,
 			 Item#roster.subscription}]}),
-    lists:foreach(fun(Resource) ->
-			  push_item(User, Server, Resource, From, Item)
-		  end, ejabberd_sm:get_user_resources(User, Server)).
-
-push_item(User, Server, Resource, _From, Item) ->
-    ResIQ = #iq{type = set, xmlns = ?NS_ROSTER,
+    Stanza = lib:iq_to_xml(
+	    #iq{type = set, xmlns = ?NS_ROSTER,
 		id = "push",
 		sub_el = [{xmlelement, "query",
 			   [{"xmlns", ?NS_ROSTER}],
-			   [item_to_xml(Item)]}]},
-    ejabberd_router:route(
-      jlib:make_jid(User, Server, Resource),
-      jlib:make_jid(User, Server, Resource),
-      jlib:iq_to_xml(ResIQ)).
+			   [item_to_xml(Item)]}]}),
+    lists:foreach(
+	fun(Resource) ->
+	    JID = jlib:make_jid(User, Server, Resource),
+	    ejabberd_router:route(JID, JID, Stanza)
+	end, ejabberd_sm:get_user_resources(User, Server)).
 
 item_to_xml(Item) ->
     Attrs1 = [{"jid", jlib:jid_to_string(Item#roster.jid)}],
@@ -743,6 +816,7 @@ shared_roster_group(Host, Group, Query, 
     AllUsers = get_opt(GroupOpts, all_users, false),
     RecentUsersDays = get_opt(GroupOpts, recent_users_days, 0),
     OnlineUsers = get_opt(GroupOpts, online_users, false),
+    NearbyUsers = get_opt(GroupOpts, nearby_users, false),
     %%Disabled = false,
     DisplayedGroups = get_opt(GroupOpts, displayed_groups, []),
     Members = mod_shared_roster:get_group_explicit_users(Host, Group),
@@ -765,6 +839,12 @@ shared_roster_group(Host, Group, Query, 
 	    true ->
 		[]
 	end ++
+	if
+	    NearbyUsers ->
+		"@nearby@\n";
+	    true ->
+		[]
+	end ++
 	[[us_to_list(Member), $\n] || Member <- Members],
     FDisplayedGroups = [[DG, $\n] || DG <- DisplayedGroups],
     FGroup =
@@ -852,6 +932,8 @@ shared_roster_group_parse_query(Host, Gr
 				  USs;
 			      "@online@" ->
 				  USs;
+			      "@nearby@" ->
+				  USs;
 			      _ ->
 				  case jlib:string_to_jid(SJID) of
 				      JID when is_record(JID, jid) ->
@@ -877,11 +959,16 @@ shared_roster_group_parse_query(Host, Gr
 		    true -> [{online_users, true}];
 		    false -> []
 		end,
+	    NearbyUsersOpt =
+		case lists:member("@nearby@", SJIDs) of
+		    true -> [{nearby_users, true}];
+		    false -> []
+		end,
 
 	    mod_shared_roster:set_group_opts(
 	      Host, Group,
 	      NameOpt ++ DispGroupsOpt ++ DescriptionOpt ++ AllUsersOpt
-		++ RecentUsersOpt ++ OnlineUsersOpt),
+		++ RecentUsersOpt ++ OnlineUsersOpt ++ NearbyUsersOpt),
 
 	    if
 		NewMembers == error -> error;
Seulement dans 1-initial-patches/ejabberd-2.0.0-beta1/src: mod_shared_roster.erl.orig
