From 88fd7b226a46f8074b3cf851a9554754063e519a Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 15 Jun 2009 17:44:04 +0000 Subject: [PATCH] Add option to restrict max offline messages by Access and ACL (EJAB-951) New option for mod_offline: access_max_user_messages. The old option user_max_messages is no longer supported. SVN Revision: 2163 --- doc/guide.html | 53 +++++++++++++++++++++++++++++++++------- doc/guide.tex | 31 ++++++++++++++++++++--- src/ejabberd.cfg.example | 5 +++- src/mod_offline.erl | 34 ++++++++++++++++---------- src/mod_offline_odbc.erl | 33 +++++++++++++++---------- 5 files changed, 116 insertions(+), 40 deletions(-) diff --git a/doc/guide.html b/doc/guide.html index 5188669ce..f64da433a 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -2423,11 +2423,31 @@ sent to an offline user will be stored on the server until that user comes online again. Thus it is very similar to how email works. Note that ejabberdctl has a command to delete expired messages (see section 4.1).

-user_max_messages
This option -is use to set a max number of offline messages per user (quota). Its -value can be either infinity or a strictly positive -integer. The default value is infinity. -

+access_max_user_messages
+This option defines which access rule will be enforced to limit +the maximum number of offline messages that a user can have (quota). +When a user has too many offline messages, any new messages that he receive are discarded, +and a resource-constraint error is returned to the sender. +The default value is max_user_offline_messages. +Then you can define an access rule with a syntax similar to +max_user_sessions (see 3.1.5). +

This example allows power users to have as much as 5000 offline messages, +administrators up to 2000, +and all the other users up to 100. +

{acl, admin, {user, "admin1", "localhost"}}.
+{acl, admin, {user, "admin2", "example.org"}}.
+{acl, poweruser, {user, "bob", "example.org"}}.
+{acl, poweruser, {user, "jane", "example.org"}}.
+
+{access, max_user_offline_messages, [ {5000, poweruser}, {2000, admin}, {100, all} ]}.
+
+{modules,
+ [
+  ...
+  {mod_offline,  [ {access_max_user_messages, max_user_offline_messages} ]},
+  ...
+ ]}.
+

3.3.11  mod_privacy

This module implements Blocking Communication (also known as Privacy Rules) as defined in section 10 from XMPP IM. If end users have support for it in @@ -2538,12 +2558,27 @@ is replaced at start time with the real virtual host name.

access_createnode
This option restricts which users are allowed to create pubsub nodes using -ACL and ACCESS. The default value is pubsub_createnode.
plugins
To specify which pubsub node plugins to use. If not defined, the default +ACL and ACCESS. The default value is pubsub_createnode.
plugins
+To specify which pubsub node plugins to use. If not defined, the default pubsub plugin is always used. -
nodetree
To specify which nodetree to use. If not defined, the default pubsub -nodetree is used. Nodetrees are default and virtual. Only one nodetree can be used +
nodetree
+To specify which nodetree to use. If not defined, the default pubsub +nodetree is used. Only one nodetree can be used per host, and is shared by all node plugins. -

Example: +

pep_sendlast_offline
+To specify whether or not we should get last published PEP items +from users in our roster which are offline when we connect. Value is true or false. +If not defined, pubsub assumes false so we only get last items of online contacts. +
last_item_cache
+To specify whether or not pubsub should cache last items. Value is true +or false. If not defined, pubsub do not cache last items. On systems with not so many nodes, +caching last items speeds up pubsub and allows to raise user connection rate. The cost is memory +usage, as every item is stored in memory. +
pep_mapping
+This allow to define a Key-Value list to choose defined node plugins on given PEP namespace. +The following example will use node_tune instead of node_pep for every PEP node with tune namespace: +
  {mod_pubsub, [{pep_mapping, [{"http://jabber.org/protocol/tune", "tune"}]}]}
+

Example:

{modules,
  [
   ...
diff --git a/doc/guide.tex b/doc/guide.tex
index b1801a8a3..a0bb82eb1 100644
--- a/doc/guide.tex
+++ b/doc/guide.tex
@@ -3132,12 +3132,35 @@ online again. Thus it is very similar to how email works. Note that
 (see section~\ref{ejabberdctl}).
 
 \begin{description}
-  \titem{user\_max\_messages}\ind{options!user\_max\_messages}This option
-  is use to set a max number of offline messages per user (quota). Its
-  value can be either \term{infinity} or a strictly positive
-  integer. The default value is \term{infinity}.
+  \titem{access\_max\_user\_messages}\ind{options!access\_max\_user\_messages}
+  This option defines which access rule will be enforced to limit
+  the maximum number of offline messages that a user can have (quota).
+  When a user has too many offline messages, any new messages that he receive are discarded,
+  and a resource-constraint error is returned to the sender.
+  The default value is \term{max\_user\_offline\_messages}.
+  Then you can define an access rule with a syntax similar to 
+  \term{max\_user\_sessions} (see \ref{configmaxsessions}).
 \end{description}
 
+This example allows power users to have as much as 5000 offline messages,
+administrators up to 2000,
+and all the other users up to 100.
+\begin{verbatim}
+{acl, admin, {user, "admin1", "localhost"}}.
+{acl, admin, {user, "admin2", "example.org"}}.
+{acl, poweruser, {user, "bob", "example.org"}}.
+{acl, poweruser, {user, "jane", "example.org"}}.
+
+{access, max_user_offline_messages, [ {5000, poweruser}, {2000, admin}, {100, all} ]}.
+
+{modules,
+ [
+  ...
+  {mod_offline,  [ {access_max_user_messages, max_user_offline_messages} ]},
+  ...
+ ]}.
+\end{verbatim}
+
 
 \makesubsection{modprivacy}{\modprivacy{}}
 \ind{modules!\modprivacy{}}\ind{Blocking Communication}\ind{Privacy Rules}\ind{protocols!RFC 3921: XMPP IM}
diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example
index 2d406c2ed..33e90789c 100644
--- a/src/ejabberd.cfg.example
+++ b/src/ejabberd.cfg.example
@@ -379,6 +379,9 @@
 %% Maximum number of simultaneous sessions allowed for a single user:
 {access, max_user_sessions, [{10, all}]}.
 
+%% Maximum number of offline messages that users can have:
+{access, max_user_offline_messages, [{5000, admin}, {100, all}]}, 
+
 %% This rule allows access only for local users:
 {access, local, [{allow, local}]}.
 
@@ -481,7 +484,7 @@
 		  {access_admin, muc_admin}
 		 ]},
   %%{mod_muc_log,[]},
-  {mod_offline,  []},
+  {mod_offline,  [{access_max_user_messages, max_user_offline_messages}]},
   {mod_privacy,  []},
   {mod_private,  []},
   %%{mod_proxy65,[]},
diff --git a/src/mod_offline.erl b/src/mod_offline.erl
index bb9ce561a..8b785bd03 100644
--- a/src/mod_offline.erl
+++ b/src/mod_offline.erl
@@ -30,7 +30,7 @@
 -behaviour(gen_mod).
 
 -export([start/2,
-	 init/1,
+	 loop/1,
 	 stop/1,
 	 store_packet/3,
 	 resend_offline_messages/2,
@@ -58,6 +58,9 @@
 -define(DEFAULT_NS, ?NS_JABBER_CLIENT).
 -define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]).
 
+%% default value for the maximum number of user messages
+-define(MAX_USER_MESSAGES, infinity).
+
 start(Host, Opts) ->
     HostB = list_to_binary(Host),
     mnesia:create_table(offline_msg,
@@ -79,22 +82,18 @@ start(Host, Opts) ->
 		       ?MODULE, webadmin_user, 50),
     ejabberd_hooks:add(webadmin_user_parse_query, HostB,
                        ?MODULE, webadmin_user_parse_query, 50),
-    MaxOfflineMsgs = gen_mod:get_opt(user_max_messages, Opts, infinity),
+    AccessMaxOfflineMsgs = gen_mod:get_opt(access_max_user_messages, Opts, max_user_offline_messages),
     register(gen_mod:get_module_proc(Host, ?PROCNAME),
-	     spawn(?MODULE, init, [MaxOfflineMsgs])).
+	     spawn(?MODULE, loop, [AccessMaxOfflineMsgs])).
 
-%% MaxOfflineMsgs is either infinity of integer > 0
-init(infinity) ->
-    loop(infinity);
-init(MaxOfflineMsgs) 
-  when is_integer(MaxOfflineMsgs), MaxOfflineMsgs > 0 ->
-    loop(MaxOfflineMsgs).
-
-loop(MaxOfflineMsgs) ->
+loop(AccessMaxOfflineMsgs) ->
     receive
 	#offline_msg{us=US} = Msg ->
 	    Msgs = receive_all(US, [Msg]),
 	    Len = length(Msgs),
+	    {User, Host} = US,
+	    MaxOfflineMsgs = get_max_user_messages(AccessMaxOfflineMsgs,
+						   User, Host),
 	    F = fun() ->
 			%% Only count messages if needed:
 			Count = if MaxOfflineMsgs =/= infinity ->
@@ -120,9 +119,18 @@ loop(MaxOfflineMsgs) ->
 			end
 		end,
 	    mnesia:transaction(F),
-	    loop(MaxOfflineMsgs);
+	    loop(AccessMaxOfflineMsgs);
 	_ ->
-	    loop(MaxOfflineMsgs)
+	    loop(AccessMaxOfflineMsgs)
+    end.
+
+%% Function copied from ejabberd_sm.erl:
+get_max_user_messages(AccessRule, LUser, Host) ->
+    case acl:match_rule(
+	   Host, AccessRule, jlib:make_jid(LUser, Host, "")) of
+	Max when is_integer(Max) -> Max;
+	infinity -> infinity;
+	_ -> ?MAX_USER_MESSAGES
     end.
 
 receive_all(US, Msgs) ->
diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl
index 7b3603f01..2d4cd787a 100644
--- a/src/mod_offline_odbc.erl
+++ b/src/mod_offline_odbc.erl
@@ -32,7 +32,7 @@
 -export([count_offline_messages/2]).
 
 -export([start/2,
-	 init/2,
+	 loop/2,
 	 stop/1,
 	 store_packet/3,
 	 pop_offline_messages/3,
@@ -57,6 +57,9 @@
 -define(DEFAULT_NS, ?NS_JABBER_CLIENT).
 -define(PREFIXED_NS, [{?NS_XMPP, ?NS_XMPP_pfx}]).
 
+%% default value for the maximum number of user messages
+-define(MAX_USER_MESSAGES, infinity).
+
 start(Host, Opts) ->
     HostB = list_to_binary(Host),
     ejabberd_hooks:add(offline_message_hook, HostB,
@@ -73,22 +76,17 @@ start(Host, Opts) ->
 		       ?MODULE, webadmin_user, 50),
     ejabberd_hooks:add(webadmin_user_parse_query, HostB,
                        ?MODULE, webadmin_user_parse_query, 50),
-    MaxOfflineMsgs = gen_mod:get_opt(user_max_messages, Opts, infinity),
+    AccessMaxOfflineMsgs = gen_mod:get_opt(access_max_user_messages, Opts, max_user_offline_messages),
     register(gen_mod:get_module_proc(Host, ?PROCNAME),
-	     spawn(?MODULE, init, [Host, MaxOfflineMsgs])).
+	     spawn(?MODULE, loop, [Host, AccessMaxOfflineMsgs])).
 
-%% MaxOfflineMsgs is either infinity of integer > 0
-init(Host, infinity) ->
-    loop(Host, infinity);
-init(Host, MaxOfflineMsgs) 
-  when is_integer(MaxOfflineMsgs), MaxOfflineMsgs > 0 ->
-    loop(Host, MaxOfflineMsgs).
-
-loop(Host, MaxOfflineMsgs) ->
+loop(Host, AccessMaxOfflineMsgs) ->
     receive
 	#offline_msg{user = User} = Msg ->
 	    Msgs = receive_all(User, [Msg]),
 	    Len = length(Msgs),
+	    MaxOfflineMsgs = get_max_user_messages(AccessMaxOfflineMsgs,
+						   User, Host),
 
 	    %% Only count existing messages if needed:
 	    Count = if MaxOfflineMsgs =/= infinity ->
@@ -128,9 +126,18 @@ loop(Host, MaxOfflineMsgs) ->
 			    ok
 		    end
 	    end,
-	    loop(Host, MaxOfflineMsgs);
+	    loop(Host, AccessMaxOfflineMsgs);
 	_ ->
-	    loop(Host, MaxOfflineMsgs)
+	    loop(Host, AccessMaxOfflineMsgs)
+    end.
+
+%% Function copied from ejabberd_sm.erl:
+get_max_user_messages(AccessRule, LUser, Host) ->
+    case acl:match_rule(
+	   Host, AccessRule, jlib:make_jid(LUser, Host, "")) of
+	Max when is_integer(Max) -> Max;
+	infinity -> infinity;
+	_ -> ?MAX_USER_MESSAGES
     end.
 
 receive_all(Username, Msgs) ->