diff --git a/doc/guide.html b/doc/guide.html index 467a4dfe5..c8160e502 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).
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} ]}, + ... + ]}. +
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.
Example: +
{mod_pubsub, [{pep_mapping, [{"http://jabber.org/protocol/tune", "tune"}]}]} +
Example:
{modules, [ ... diff --git a/doc/guide.tex b/doc/guide.tex index 1406b0523..66747bbe5 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 b0fcecadb..ebcd44ed0 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 e3898eb4f..c9fe276c1 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, @@ -52,6 +52,9 @@ -define(PROCNAME, ejabberd_offline). -define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000). +%% default value for the maximum number of user messages +-define(MAX_USER_MESSAGES, infinity). + start(Host, Opts) -> mnesia:create_table(offline_msg, [{disc_only_copies, [node()]}, @@ -72,22 +75,18 @@ start(Host, Opts) -> ?MODULE, webadmin_user, 50), ejabberd_hooks:add(webadmin_user_parse_query, Host, ?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 -> @@ -113,9 +112,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 3a61374dc..507da1f11 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, @@ -51,6 +51,9 @@ -define(PROCNAME, ejabberd_offline). -define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000). +%% default value for the maximum number of user messages +-define(MAX_USER_MESSAGES, infinity). + start(Host, Opts) -> ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, store_packet, 50), @@ -66,22 +69,17 @@ start(Host, Opts) -> ?MODULE, webadmin_user, 50), ejabberd_hooks:add(webadmin_user_parse_query, Host, ?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 -> @@ -125,9 +123,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) ->