[ejabberd] Include OLPC's @online@ patch - EJAB-1391

Peter Lemenkov peter at fedoraproject.org
Tue Jan 25 15:56:20 UTC 2011


commit 907904f9906facde52f617c8d4b7f2248a1c21c9
Author: Martin Langhoff <martin at laptop.org>
Date:   Mon Jan 24 20:57:17 2011 -0500

    Include OLPC's @online@ patch - EJAB-1391

 ejabberd-0011-online-shared-roster-grp.patch |  322 ++++++++++++++++++++++++++
 ejabberd.spec                                |    8 +-
 2 files changed, 329 insertions(+), 1 deletions(-)
---
diff --git a/ejabberd-0011-online-shared-roster-grp.patch b/ejabberd-0011-online-shared-roster-grp.patch
new file mode 100644
index 0000000..5084f60
--- /dev/null
+++ b/ejabberd-0011-online-shared-roster-grp.patch
@@ -0,0 +1,322 @@
+From f98185d4da9ed34df7e5e3bf7f0b8e4b1b169e6c Mon Sep 17 00:00:00 2001
+From: Martin Langhoff <martin at laptop.org>
+Date: Mon, 24 Jan 2011 17:55:22 -0500
+Subject: [PATCH] New version of the @online@ patch originally by Collabora.
+
+Notes:
+
+ - fixed a typo in is_user_in_group
+ - simplified user_available and unset_presence hook handlers
+ - the presence push is mediated via the group rather than
+   per user - this may reduce memory footprint... _if_ ejabberd
+   has some smart optimisation in that codepath
+ - it assumes that any group with membership @online@ _displays_
+   online as well -- this is a simplification and breaks the
+   decoupling that ejabberd has in this regard.
+---
+ src/mod_shared_roster.erl |  154 ++++++++++++++++++++++++++++++++++++++++-----
+ 1 files changed, 137 insertions(+), 17 deletions(-)
+
+diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl
+index 64a8291..2f23201 100644
+--- a/src/mod_shared_roster.erl
++++ b/src/mod_shared_roster.erl
+@@ -37,6 +37,8 @@
+ 	 process_item/2,
+ 	 in_subscription/6,
+ 	 out_subscription/4,
++	 user_available/1,
++	 unset_presence/4,
+ 	 register_user/2,
+ 	 remove_user/2,
+ 	 list_groups/1,
+@@ -45,7 +47,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,
+ 	 is_user_in_group/3,
+ 	 add_user_to_group/3,
+@@ -85,6 +87,10 @@ start(Host, _Opts) ->
+         	       ?MODULE, get_jid_info, 70),
+     ejabberd_hooks:add(roster_process_item, Host,
+ 		       ?MODULE, process_item, 50),
++    ejabberd_hooks:add(user_available_hook, Host,
++		       ?MODULE, user_available, 50),
++    ejabberd_hooks:add(unset_presence_hook, Host,
++		       ?MODULE, unset_presence, 50),
+     ejabberd_hooks:add(register_user, Host,
+ 		       ?MODULE, register_user, 50),
+     ejabberd_hooks:add(remove_user, Host,
+@@ -109,6 +115,10 @@ stop(Host) ->
+         		  ?MODULE, get_jid_info, 70),
+     ejabberd_hooks:delete(roster_process_item, Host,
+ 			  ?MODULE, process_item, 50),
++    ejabberd_hooks:delete(user_available_hook, Host,
++			  ?MODULE, user_available, 50),
++    ejabberd_hooks:delete(unset_presence_hook, Host,
++			  ?MODULE, unset_presence, 50),
+     ejabberd_hooks:delete(register_user, Host,
+ 			  ?MODULE, register_user, 50),
+     ejabberd_hooks:delete(remove_user, Host,
+@@ -132,7 +142,7 @@ get_user_roster(Items, US) ->
+ 						   GroupName,
+ 						   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
+@@ -310,7 +320,7 @@ get_subscription_lists({F, T}, User, Server) ->
+ 	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)}.
+@@ -329,7 +339,7 @@ get_jid_info({Subscription, Groups}, User, Server, JID) ->
+ 		    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} ->
+@@ -371,7 +381,7 @@ process_subscription(Direction, User, Server, JID, _Type, Acc) ->
+ 	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 ->
+@@ -470,21 +480,41 @@ get_group_opt(Host, Group, Opt, Default) ->
+ 	    Default
+     end.
+ 
+-get_group_users(Host, Group) ->
++-record(last_activity, {us, timestamp, status}).
++-record(session, {sid, usr, us, priority, info}).
++
++get_online_users(Host) ->
++    lists:usort([{U, S} || {U, S, _} <- ejabberd_sm:get_vh_session_list(Host)]).
++
++get_group_users(User, Host, Group) ->
+     case get_group_opt(Host, Group, all_users, false) of
+ 	true ->
+ 	    ejabberd_auth:get_vh_registered_users(Host);
+ 	false ->
+ 	    []
+-    end ++ get_group_explicit_users(Host, Group).
+-
+-get_group_users(_User, Host, Group, GroupOpts) ->
++    end ++
++    case get_group_opt(Host, Group, online_users, false) of
++	true ->
++	    get_online_users(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 ++ get_group_explicit_users(Host, Group).
++    end ++
++    case proplists:get_value(online_users, GroupOpts, false) of
++	true ->
++	    get_online_users(Host);
++	false ->
++	    []
++    end ++
++    get_group_explicit_users(Host, Group).
+ 
+ %% @spec (Host::string(), Group::string()) -> [{User::string(), Server::string()}]
+ get_group_explicit_users(Host, Group) ->
+@@ -502,11 +532,20 @@ get_group_explicit_users(Host, Group) ->
+ get_group_name(Host, Group) ->
+     get_group_opt(Host, Group, name, Group).
+ 
+-%% Get list of names of groups that have @all@ in the memberlist
++%% Get list of names of groups that have @all@/@online@/etc in the memberlist
+ get_special_users_groups(Host) ->
+     lists:filter(
+       fun(Group) ->
+-	      get_group_opt(Host, Group, all_users, false)
++	get_group_opt(Host, Group, all_users, false) orelse
++	get_group_opt(Host, Group, online_users, false)
++      end,
++      list_groups(Host)).
++
++%% Get list of names of groups that have @online@ in the memberlist
++get_special_users_groups_online(Host) ->
++    lists:filter(
++      fun(Group) ->
++	get_group_opt(Host, Group, online_users, false)
+       end,
+       list_groups(Host)).
+ 
+@@ -565,7 +604,7 @@ get_user_displayed_groups(US) ->
+ is_user_in_group({_U, S} = US, Group, Host) ->
+     case catch mnesia:dirty_match_object(
+ 		 #sr_user{us=US, group_host={Group, Host}}) of
+-        [] -> lists:member(US, get_group_users(S, Group));
++        [] -> lists:member(US, get_group_users(_U, S, Group));
+ 	_  -> true
+     end.
+ 
+@@ -632,7 +671,7 @@ push_members_to_user(LUser, LServer, Group, Host, Subscription) ->
+     GroupsOpts = groups_with_opts(LServer),
+     GroupOpts = proplists:get_value(Group, GroupsOpts, []),
+     GroupName = proplists:get_value(name, GroupOpts, Group),
+-    Members = get_group_users(Host, Group),
++    Members = get_group_users(LUser, Host, Group),
+     lists:foreach(
+       fun({U, S}) ->
+ 	      push_roster_item(LUser, LServer, U, S, GroupName, Subscription)
+@@ -675,7 +714,7 @@ push_user_to_group(LUser, LServer, Group, GroupName, Subscription) ->
+     lists:foreach(
+       fun({U, S}) ->
+ 	      push_roster_item(U, S, LUser, LServer, GroupName, Subscription)
+-      end, get_group_users(LServer, Group)).
++      end, get_group_users(LUser, LServer, Group)).
+ 
+ %% Get list of groups to which this group is displayed
+ displayed_to_groups(GroupName, LServer) ->
+@@ -757,6 +796,72 @@ ask_to_pending(subscribe) -> out;
+ ask_to_pending(unsubscribe) -> none;
+ ask_to_pending(Ask) -> Ask.
+ 
++%% get a roster item for a contact from a particular user's
++%% perspective, considering both normal and shared roster items
++%% FIXME: is there a more efficient way to do this?
++get_user_roster_item(FromUS, ToUS) ->
++    {FUser, FServer} = FromUS,
++    case catch ejabberd_hooks:run_fold(roster_get, FServer, [], [ToUS]) of
++      Items when is_list(Items) ->
++	case [I || I <- Items, I#roster.jid == {FUser, FServer, []}] of
++	  [Item | _ ] ->
++	    Item;
++	  [] ->
++	    false
++	end;
++      _ ->
++	error
++    end.
++
++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(Resources)]),
++
++    case length(Resources) of
++      %% first session for this user
++      1 ->
++
++        %% This is a simplification - we ignore he 'display'
++        %% property - @online@ is always reflective.
++        OnlineGroups = get_special_users_groups_online(LServer),
++
++        lists:foreach(
++            fun(OG) ->
++	         ?INFO_MSG("user_available: pushing  ~p @ ~p grp ~p",
++                           [LUser, LServer, OG ]),
++	         push_user_to_displayed(LUser, LServer, OG, both)
++                 end, OnlineGroups);
++
++      _ ->
++        ok
++    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(Resources)]),
++
++    %% if user has no resources left...
++    case length(Resources) of
++      0 ->
++        %% This is a simplification - we ignore he 'display'
++        %% property - @online@ is always reflective.
++        OnlineGroups = get_special_users_groups_online(LServer),
++
++	%% for each of these groups...
++        lists:foreach(
++	  fun(OG) ->
++             %% Push removal of the old user to members of groups where the group that this user was members was displayed
++             push_user_to_displayed(LUser, LServer, OG, remove),
++             %% Push removal of members of groups that where displayed to the group which this user has left
++             push_displayed_to_user(LUser, LServer, OG, LServer, remove)          
++	     end, OnlineGroups);
++      _ ->
++	ok
++    end.
+ 
+ %%---------------------
+ %% Web Admin
+@@ -860,6 +965,7 @@ shared_roster_group(Host, Group, Query, Lang) ->
+     Name = get_opt(GroupOpts, name, ""),
+     Description = get_opt(GroupOpts, description, ""),
+     AllUsers = get_opt(GroupOpts, all_users, false),
++    OnlineUsers = get_opt(GroupOpts, online_users, false),
+     %%Disabled = false,
+     DisplayedGroups = get_opt(GroupOpts, displayed_groups, []),
+     Members = mod_shared_roster:get_group_explicit_users(Host, Group),
+@@ -869,7 +975,14 @@ shared_roster_group(Host, Group, Query, Lang) ->
+ 		"@all@\n";
+ 	    true ->
+ 		[]
+-	end ++ [[us_to_list(Member), $\n] || Member <- Members],
++	end ++
++	if
++	    OnlineUsers ->
++		"@online@\n";
++	    true ->
++		[]
++	end ++
++	[[us_to_list(Member), $\n] || Member <- Members],
+     FDisplayedGroups = [[DG, $\n] || DG <- DisplayedGroups],
+     DescNL = length(element(2, regexp:split(Description, "\n"))),
+     FGroup =
+@@ -953,6 +1066,8 @@ shared_roster_group_parse_query(Host, Group, Query) ->
+ 			  case SJID of
+ 			      "@all@" ->
+ 				  USs;
++			      "@online@" ->
++				  USs;
+ 			      _ ->
+ 				  case jlib:string_to_jid(SJID) of
+ 				      JID when is_record(JID, jid) ->
+@@ -967,10 +1082,15 @@ shared_roster_group_parse_query(Host, Group, Query) ->
+ 		    true -> [{all_users, true}];
+ 		    false -> []
+ 		end,
++	    OnlineUsersOpt =
++		case lists:member("@online@", SJIDs) of
++		    true -> [{online_users, true}];
++		    false -> []
++		end,
+ 
+ 	    mod_shared_roster:set_group_opts(
+ 	      Host, Group,
+-	      NameOpt ++ DispGroupsOpt ++ DescriptionOpt ++ AllUsersOpt),
++	      NameOpt ++ DispGroupsOpt ++ DescriptionOpt ++ AllUsersOpt ++ OnlineUsersOpt),
+ 
+ 	    if
+ 		NewMembers == error -> error;
+-- 
+1.7.3.4
+
diff --git a/ejabberd.spec b/ejabberd.spec
index b26a5b2..3966dd7 100644
--- a/ejabberd.spec
+++ b/ejabberd.spec
@@ -11,7 +11,7 @@
 
 Name:           ejabberd
 Version:        2.1.6
-Release:        1%{?dist}
+Release:        2%{?dist}
 Summary:        A distributed, fault-tolerant Jabber/XMPP server
 
 Group:          Applications/Internet
@@ -47,6 +47,8 @@ Patch8: ejabberd-0008-Support-SASL-GSSAPI-authentication-thanks-to-Mikael-.patch
 Patch9: ejabberd-0009-Added-old-modules-for-Active-Directory.patch
 # Correct version in configure (DON'T FORGET TO REMOVE IN THE NEXT VERSION)
 Patch10: ejabberd-0010-last-minute-fix-correct-version-in-configure.patch
+# OLPC's @online@ shared roster group patch - EJAB-1391
+Patch11: ejabberd-0011-online-shared-roster-grp.patch
 
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
@@ -112,6 +114,7 @@ Documentation for ejabberd.
 %patch8 -p1 -b .gssapi
 %patch9 -p1 -b .ad_stuff
 %patch10 -p1 -b .fix_version
+%patch11 -p1 -b .online_srg
 touch -r src/configure.fix_version src/configure
 
 
@@ -338,6 +341,9 @@ rm -rf %{buildroot}
 %doc %{_docdir}/%{name}-%{version}/*.txt
 
 %changelog
+* Tue Jan 25 2011 Martin Langhoff <martin at laptop.org> 2.1.6-2
+- Apply rebased @online@ patch from OLPC - EJAB-1391
+
 * Tue Dec 14 2010 Peter Lemenkov <lemenkov at gmail.com> 2.1.6-1
 - Ver. 2.1.6 (Bugfix release)
 


More information about the scm-commits mailing list