diff --git a/ChangeLog b/ChangeLog index d959002e8..cfba33ef8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2007-08-03 Mickael Remond + + * src/mod_announce.erl: Added support to all the announce features + described in documentation. Access to all announce features + through command line, adhoc commands and disco (Thanks to + Badlop) (EJAB-18). + * src/gen_mod.erl: Likewise. + * doc/guide.tex: Likewise. + 2007-08-02 Alexey Shchepin * src/mod_muc/mod_muc.erl: Added default_room_options option diff --git a/doc/guide.html b/doc/guide.html index a61d0893c..8012e5b76 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -1410,7 +1410,7 @@ with:

This module enables configured users to broadcast announcements and to set the message of the day (MOTD). Configured users can do these actions with their -Jabber client by sending messages to specific JIDs. These JIDs are listed in +Jabber client using Ad-hoc commands or by sending messages to specific JIDs. These JIDs are listed in next paragraph. The first JID in each entry will apply only to the virtual host example.org, while the JID between brackets will apply to all virtual hosts: @@ -1463,7 +1463,9 @@ Only administrators can send announcements: {mod_announce, [{access, announce}]}, ... ]}. - +

Note that mod_announce can be resource intensive on large +deployments as it can broadcast lot of messages. This module should be +disabled for instances of ejabberd with hundreds of thousands users.

3.3.4  mod_disco

This module adds support for Service Discovery (XEP-0030). With diff --git a/doc/guide.tex b/doc/guide.tex index 8d8c1f0d8..ed608075b 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -1744,7 +1744,7 @@ Examples: This module enables configured users to broadcast announcements and to set the message of the day (MOTD). Configured users can do these actions with their -\Jabber{} client by sending messages to specific JIDs. These JIDs are listed in +\Jabber{} client using Ad-hoc commands or by sending messages to specific JIDs. These JIDs are listed in next paragraph. The first JID in each entry will apply only to the virtual host \jid{example.org}, while the JID between brackets will apply to all virtual hosts: @@ -1790,7 +1790,7 @@ Examples: ]}. \end{verbatim} \item Administrators as well as the direction can send announcements: - \begin{verbatim} +\begin{verbatim} {acl, direction, {user, "big_boss", "example.org"}}. {acl, direction, {user, "assistant", "example.org"}}. {acl, admins, {user, "admin", "example.org"}}. @@ -1807,6 +1807,10 @@ Examples: \end{verbatim} \end{itemize} +Note that \modannounce{} can be resource intensive on large +deployments as it can broadcast lot of messages. This module should be +disabled for instances of ejabberd with hundreds of thousands users. + \subsection{\moddisco{}} \label{moddisco} \ind{modules!\moddisco{}}\ind{protocols!XEP-0030: Service Discovery}\ind{protocols!XEP-0011: Jabber Browsing}\ind{protocols!XEP-0094: Agent Information} diff --git a/src/gen_mod.erl b/src/gen_mod.erl index 7ba6db182..eed3e4405 100644 --- a/src/gen_mod.erl +++ b/src/gen_mod.erl @@ -107,6 +107,23 @@ get_opt(Opt, Opts, Default) -> Val end. +get_module_opt(global, Module, Opt, Default) -> + Hosts = ?MYHOSTS, + [Value | Values] = lists:map( + fun(Host) -> + get_module_opt(Host, Module, Opt, Default) + end, + Hosts), + Same_all = lists:all( + fun(Other_value) -> + Other_value == Value + end, + Values), + case Same_all of + true -> Value; + false -> Default + end; + get_module_opt(Host, Module, Opt, Default) -> OptsList = ets:lookup(ejabberd_modules, {Module, Host}), case OptsList of diff --git a/src/mod_announce.erl b/src/mod_announce.erl index 8cabf748a..deccafcb0 100644 --- a/src/mod_announce.erl +++ b/src/mod_announce.erl @@ -57,6 +57,9 @@ loop() -> {announce_all, From, To, Packet} -> announce_all(From, To, Packet), loop(); + {announce_all_hosts_all, From, To, Packet} -> + announce_all_hosts_all(From, To, Packet), + loop(); {announce_online, From, To, Packet} -> announce_online(From, To, Packet), loop(); @@ -66,12 +69,21 @@ loop() -> {announce_motd, From, To, Packet} -> announce_motd(From, To, Packet), loop(); + {announce_all_hosts_motd, From, To, Packet} -> + announce_all_hosts_motd(From, To, Packet), + loop(); {announce_motd_update, From, To, Packet} -> announce_motd_update(From, To, Packet), loop(); + {announce_all_hosts_motd_update, From, To, Packet} -> + announce_all_hosts_motd_update(From, To, Packet), + loop(); {announce_motd_delete, From, To, Packet} -> announce_motd_delete(From, To, Packet), loop(); + {announce_all_hosts_motd_delete, From, To, Packet} -> + announce_all_hosts_motd_delete(From, To, Packet), + loop(); _ -> loop() end. @@ -100,6 +112,9 @@ announce(From, To, Packet) -> {"announce/all", "message"} -> Proc ! {announce_all, From, To, Packet}, stop; + {"announce/all-hosts/all", "message"} -> + Proc ! {announce_all_hosts_all, From, To, Packet}, + stop; {"announce/online", "message"} -> Proc ! {announce_online, From, To, Packet}, stop; @@ -109,12 +124,21 @@ announce(From, To, Packet) -> {"announce/motd", "message"} -> Proc ! {announce_motd, From, To, Packet}, stop; + {"announce/all-hosts/motd", "message"} -> + Proc ! {announce_all_hosts_motd, From, To, Packet}, + stop; {"announce/motd/update", "message"} -> Proc ! {announce_motd_update, From, To, Packet}, stop; + {"announce/all-hosts/motd/update", "message"} -> + Proc ! {announce_all_hosts_motd_update, From, To, Packet}, + stop; {"announce/motd/delete", "message"} -> Proc ! {announce_motd_delete, From, To, Packet}, stop; + {"announce/all-hosts/motd/delete", "message"} -> + Proc ! {announce_all_hosts_motd_delete, From, To, Packet}, + stop; _ -> ok end; @@ -134,16 +158,24 @@ disco_identity(Acc, _From, _To, Node, Lang) -> case Node of "announce/all" -> ?INFO_COMMAND(Lang, Node); - "announce/all-hosts/online" -> + "announce/all-hosts/all" -> ?INFO_COMMAND(Lang, Node); "announce/online" -> ?INFO_COMMAND(Lang, Node); + "announce/all-hosts/online" -> + ?INFO_COMMAND(Lang, Node); "announce/motd" -> ?INFO_COMMAND(Lang, Node); + "announce/all-hosts/motd" -> + ?INFO_COMMAND(Lang, Node); "announce/motd/delete" -> ?INFO_COMMAND(Lang, Node); + "announce/all-hosts/motd/delete" -> + ?INFO_COMMAND(Lang, Node); "announce/motd/update" -> ?INFO_COMMAND(Lang, Node); + "announce/all-hosts/motd/update" -> + ?INFO_COMMAND(Lang, Node); _ -> Acc end. @@ -176,7 +208,12 @@ disco_features(Acc, From, #jid{lserver = LServer} = _To, end; disco_features(Acc, From, #jid{lserver = LServer} = _To, - "announce/all-hosts/online", _Lang) -> + Node, _Lang) + when (Node == "announce/all-hosts/online") + or (Node == "announce/all-hosts/all") + or (Node == "announce/all-hosts/motd") + or (Node == "announce/all-hosts/motd/update") + or (Node == "announce/all-hosts/motd/delete") -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -257,8 +294,12 @@ disco_items(Acc, From, #jid{lserver = LServer} = To, "announce", Lang) -> announce_items(Acc, From, To, Lang) end; -disco_items(Acc, From, #jid{lserver = LServer} = _To, - "announce/all-hosts/online", _Lang) -> +disco_items(Acc, From, #jid{lserver = LServer} = _To, Node, _Lang) + when (Node == "announce/all-hosts/online") + or (Node == "announce/all-hosts/all") + or (Node == "announce/all-hosts/motd") + or (Node == "announce/all-hosts/motd/update") + or (Node == "announce/all-hosts/motd/delete") -> case gen_mod:is_loaded(LServer, mod_adhoc) of false -> Acc; @@ -308,7 +349,11 @@ announce_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, Lang) Access2 = gen_mod:get_module_opt(global, ?MODULE, access, none), Nodes2 = case acl:match_rule(global, Access2, From) of allow -> - [?NODE_TO_ITEM(Lang, Server, "announce/all-hosts/online")]; + [?NODE_TO_ITEM(Lang, Server, "announce/all-hosts/all"), + ?NODE_TO_ITEM(Lang, Server, "announce/all-hosts/online"), + ?NODE_TO_ITEM(Lang, Server, "announce/all-hosts/motd"), + ?NODE_TO_ITEM(Lang, Server, "announce/all-hosts/motd/update"), + ?NODE_TO_ITEM(Lang, Server, "announce/all-hosts/motd/delete")]; deny -> [] end, @@ -335,7 +380,12 @@ announce_items(Acc, From, #jid{lserver = LServer, server = Server} = _To, Lang) announce_commands(_Acc, From, To, #adhoc_request{ - node = "announce/all-hosts/online"} = Request) -> + node = Node} = Request) + when (Node == "announce/all-hosts/online") + or (Node == "announce/all-hosts/all") + or (Node == "announce/all-hosts/motd") + or (Node == "announce/all-hosts/motd/update") + or (Node == "announce/all-hosts/motd/delete") -> Access = gen_mod:get_module_opt(global, ?MODULE, access, none), Allow = acl:match_rule(global, Access, From), ?COMMANDS_RESULT(Allow, From, To, Request); @@ -400,7 +450,8 @@ generate_adhoc_form(Lang, Node) -> {"type", "form"}], [{xmlelement, "title", [], [{xmlcdata, get_title(Lang, Node)}]}] ++ - if Node == "announce/motd/delete" -> + if (Node == "announce/motd/delete") + or (Node == "announce/all-hosts/motd/delete") -> [{xmlelement, "field", [{"var", "confirm"}, {"type", "boolean"}, @@ -485,6 +536,13 @@ handle_adhoc_form(From, #jid{lserver = LServer} = To, true -> adhoc:produce_response(Response) end; + {"announce/all-hosts/motd/delete", _} -> + if Confirm -> + Proc ! {announce_all_hosts_motd_delete, From, To, Packet}, + adhoc:produce_response(Response); + true -> + adhoc:produce_response(Response) + end; {_, []} -> %% An announce message with no body is definitely an operator error. %% Throw an error and give him/her a chance to send message again. @@ -497,6 +555,9 @@ handle_adhoc_form(From, #jid{lserver = LServer} = To, {"announce/all", _} -> Proc ! {announce_all, From, To, Packet}, adhoc:produce_response(Response); + {"announce/all-hosts/all", _} -> + Proc ! {announce_all_hosts_all, From, To, Packet}, + adhoc:produce_response(Response); {"announce/online", _} -> Proc ! {announce_online, From, To, Packet}, adhoc:produce_response(Response); @@ -506,9 +567,15 @@ handle_adhoc_form(From, #jid{lserver = LServer} = To, {"announce/motd", _} -> Proc ! {announce_motd, From, To, Packet}, adhoc:produce_response(Response); + {"announce/all-hosts/motd", _} -> + Proc ! {announce_all_hosts_motd, From, To, Packet}, + adhoc:produce_response(Response); {"announce/motd/update", _} -> Proc ! {announce_motd_update, From, To, Packet}, adhoc:produce_response(Response); + {"announce/all-hosts/motd/update", _} -> + Proc ! {announce_all_hosts_motd_update, From, To, Packet}, + adhoc:produce_response(Response); _ -> %% This can't happen, as we haven't registered any other %% command nodes. @@ -519,16 +586,24 @@ get_title(Lang, "announce") -> translate:translate(Lang, "Announcements"); get_title(Lang, "announce/all") -> translate:translate(Lang, "Send announcement to all users"); +get_title(Lang, "announce/all-hosts/all") -> + translate:translate(Lang, "Send announcement to all users on all hosts"); get_title(Lang, "announce/online") -> translate:translate(Lang, "Send announcement to all online users"); get_title(Lang, "announce/all-hosts/online") -> translate:translate(Lang, "Send announcement to all online users on all hosts"); get_title(Lang, "announce/motd") -> translate:translate(Lang, "Set message of the day and send to online users"); +get_title(Lang, "announce/all-hosts/motd") -> + translate:translate(Lang, "Set message of the day on all hosts and send to online users"); get_title(Lang, "announce/motd/update") -> translate:translate(Lang, "Update message of the day (don't send)"); +get_title(Lang, "announce/all-hosts/motd/update") -> + translate:translate(Lang, "Update message of the day on all hosts (don't send)"); get_title(Lang, "announce/motd/delete") -> - translate:translate(Lang, "Delete message of the day"). + translate:translate(Lang, "Delete message of the day"); +get_title(Lang, "announce/all-hosts/motd/delete") -> + translate:translate(Lang, "Delete message of the day on all hosts"). %------------------------------------------------------------------------- @@ -548,6 +623,21 @@ announce_all(From, To, Packet) -> end, ejabberd_auth:get_vh_registered_users(Host)) end. +announce_all_hosts_all(From, To, Packet) -> + Access = gen_mod:get_module_opt(global, ?MODULE, access, none), + case acl:match_rule(global, Access, From) of + deny -> + Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + ejabberd_router:route(To, From, Err); + allow -> + Local = jlib:make_jid("", To#jid.server, ""), + lists:foreach( + fun({User, Server}) -> + Dest = jlib:make_jid(User, Server, ""), + ejabberd_router:route(Local, Dest, Packet) + end, ejabberd_auth:dirty_get_registered_users()) + end. + announce_online(From, To, Packet) -> Host = To#jid.lserver, Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), @@ -589,18 +679,32 @@ announce_motd(From, To, Packet) -> Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), ejabberd_router:route(To, From, Err); allow -> - announce_motd_update(To#jid.lserver, Packet), - Sessions = ejabberd_sm:get_vh_session_list(Host), - announce_online1(Sessions, To#jid.server, Packet), - F = fun() -> - lists:foreach( - fun({U, S, _R}) -> - mnesia:write(#motd_users{us = {U, S}}) - end, Sessions) - end, - mnesia:transaction(F) + announce_motd(Host, Packet) end. +announce_all_hosts_motd(From, To, Packet) -> + Access = gen_mod:get_module_opt(global, ?MODULE, access, none), + case acl:match_rule(global, Access, From) of + deny -> + Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + ejabberd_router:route(To, From, Err); + allow -> + Hosts = ?MYHOSTS, + [announce_motd(Host, Packet) || Host <- Hosts] + end. + +announce_motd(Host, Packet) -> + announce_motd_update(Host, Packet), + Sessions = ejabberd_sm:get_vh_session_list(Host), + announce_online1(Sessions, Host, Packet), + F = fun() -> + lists:foreach( + fun({U, S, _R}) -> + mnesia:write(#motd_users{us = {U, S}}) + end, Sessions) + end, + mnesia:transaction(F). + announce_motd_update(From, To, Packet) -> Host = To#jid.lserver, Access = gen_mod:get_module_opt(Host, ?MODULE, access, none), @@ -612,6 +716,17 @@ announce_motd_update(From, To, Packet) -> announce_motd_update(Host, Packet) end. +announce_all_hosts_motd_update(From, To, Packet) -> + Access = gen_mod:get_module_opt(global, ?MODULE, access, none), + case acl:match_rule(global, Access, From) of + deny -> + Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + ejabberd_router:route(To, From, Err); + allow -> + Hosts = ?MYHOSTS, + [announce_motd_update(Host, Packet) || Host <- Hosts] + end. + announce_motd_update(LServer, Packet) -> announce_motd_delete(LServer), F = fun() -> @@ -630,6 +745,17 @@ announce_motd_delete(From, To, Packet) -> announce_motd_delete(Host) end. +announce_all_hosts_motd_delete(From, To, Packet) -> + Access = gen_mod:get_module_opt(global, ?MODULE, access, none), + case acl:match_rule(global, Access, From) of + deny -> + Err = jlib:make_error_reply(Packet, ?ERR_FORBIDDEN), + ejabberd_router:route(To, From, Err); + allow -> + Hosts = ?MYHOSTS, + [announce_motd_delete(Host) || Host <- Hosts] + end. + announce_motd_delete(LServer) -> F = fun() -> mnesia:delete({motd, LServer}), @@ -754,4 +880,3 @@ update_motd_users_table() -> ?INFO_MSG("Recreating motd_users table", []), mnesia:transform_table(motd_users, ignore, Fields) end. -