mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-10 15:47:30 +01:00
4098c3ecba
SVN Revision: 370
329 lines
9.4 KiB
Erlang
329 lines
9.4 KiB
Erlang
%%%----------------------------------------------------------------------
|
|
%%% File : mod_announce.erl
|
|
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
|
%%% Purpose : Manage announce messages
|
|
%%% Created : 11 Aug 2003 by Alexey Shchepin <alexey@sevcom.net>
|
|
%%% Id : $Id$
|
|
%%%----------------------------------------------------------------------
|
|
|
|
-module(mod_announce).
|
|
-author('alexey@sevcom.net').
|
|
|
|
-behaviour(gen_mod).
|
|
|
|
-export([start/2,
|
|
init/0,
|
|
stop/1,
|
|
announce/3,
|
|
send_motd/1]).
|
|
|
|
-include("ejabberd.hrl").
|
|
-include("jlib.hrl").
|
|
|
|
-record(motd, {server, packet}).
|
|
-record(motd_users, {us, dummy = []}).
|
|
|
|
-define(PROCNAME, ejabberd_announce).
|
|
|
|
start(Host, _Opts) ->
|
|
mnesia:create_table(motd, [{disc_copies, [node()]},
|
|
{attributes, record_info(fields, motd)}]),
|
|
mnesia:create_table(motd_users, [{disc_copies, [node()]},
|
|
{attributes, record_info(fields, motd_users)}]),
|
|
update_tables(),
|
|
ejabberd_hooks:add(local_send_to_resource_hook, Host,
|
|
?MODULE, announce, 50),
|
|
ejabberd_hooks:add(user_available_hook, Host,
|
|
?MODULE, send_motd, 50),
|
|
register(gen_mod:get_module_proc(Host, ?PROCNAME),
|
|
proc_lib:spawn(?MODULE, init, [])).
|
|
|
|
init() ->
|
|
loop().
|
|
|
|
loop() ->
|
|
receive
|
|
{announce_all, From, To, Packet} ->
|
|
announce_all(From, To, Packet),
|
|
loop();
|
|
{announce_online, From, To, Packet} ->
|
|
announce_online(From, To, Packet),
|
|
loop();
|
|
{announce_all_hosts_online, From, To, Packet} ->
|
|
announce_all_hosts_online(From, To, Packet),
|
|
loop();
|
|
{announce_motd, From, To, Packet} ->
|
|
announce_motd(From, To, Packet),
|
|
loop();
|
|
{announce_motd_update, From, To, Packet} ->
|
|
announce_motd_update(From, To, Packet),
|
|
loop();
|
|
{announce_motd_delete, From, To, Packet} ->
|
|
announce_motd_delete(From, To, Packet),
|
|
loop();
|
|
_ ->
|
|
loop()
|
|
end.
|
|
|
|
stop(Host) ->
|
|
ejabberd_hooks:delete(local_send_to_resource_hook, Host,
|
|
?MODULE, announce, 50),
|
|
ejabberd_hooks:delete(sm_register_connection_hook, Host,
|
|
?MODULE, send_motd, 50),
|
|
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
|
exit(whereis(Proc), stop),
|
|
{wait, Proc}.
|
|
|
|
announce(From, To, Packet) ->
|
|
case To of
|
|
#jid{luser = "", lresource = Res} ->
|
|
{xmlelement, Name, _Attrs, _Els} = Packet,
|
|
Proc = gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME),
|
|
case {Res, Name} of
|
|
{"announce/all", "message"} ->
|
|
Proc ! {announce_all, From, To, Packet},
|
|
stop;
|
|
{"announce/online", "message"} ->
|
|
Proc ! {announce_online, From, To, Packet},
|
|
stop;
|
|
{"announce/all-hosts/online", "message"} ->
|
|
Proc ! {announce_all_hosts_online, From, To, Packet},
|
|
stop;
|
|
{"announce/motd", "message"} ->
|
|
Proc ! {announce_motd, From, To, Packet},
|
|
stop;
|
|
{"announce/motd/update", "message"} ->
|
|
Proc ! {announce_motd_update, From, To, Packet},
|
|
stop;
|
|
{"announce/motd/delete", "message"} ->
|
|
Proc ! {announce_motd_delete, From, To, Packet},
|
|
stop;
|
|
_ ->
|
|
ok
|
|
end;
|
|
_ ->
|
|
ok
|
|
end.
|
|
|
|
announce_all(From, To, Packet) ->
|
|
Host = To#jid.lserver,
|
|
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
|
case acl:match_rule(Host, Access, From) of
|
|
deny ->
|
|
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
|
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:get_vh_registered_users(Host))
|
|
end.
|
|
|
|
announce_online(From, To, Packet) ->
|
|
Host = To#jid.lserver,
|
|
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
|
case acl:match_rule(Host, Access, From) of
|
|
deny ->
|
|
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
|
ejabberd_router:route(To, From, Err);
|
|
allow ->
|
|
announce_online1(ejabberd_sm:get_vh_session_list(Host),
|
|
To#jid.server,
|
|
Packet)
|
|
end.
|
|
|
|
announce_all_hosts_online(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_NOT_ALLOWED),
|
|
ejabberd_router:route(To, From, Err);
|
|
allow ->
|
|
announce_online1(ejabberd_sm:dirty_get_sessions_list(),
|
|
To#jid.server,
|
|
Packet)
|
|
end.
|
|
|
|
announce_online1(Sessions, Server, Packet) ->
|
|
Local = jlib:make_jid("", Server, ""),
|
|
lists:foreach(
|
|
fun({U, S, R}) ->
|
|
Dest = jlib:make_jid(U, S, R),
|
|
ejabberd_router:route(Local, Dest, Packet)
|
|
end, Sessions).
|
|
|
|
announce_motd(From, To, Packet) ->
|
|
Host = To#jid.lserver,
|
|
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
|
case acl:match_rule(Host, Access, From) of
|
|
deny ->
|
|
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
|
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)
|
|
end.
|
|
|
|
announce_motd_update(From, To, Packet) ->
|
|
Host = To#jid.lserver,
|
|
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
|
case acl:match_rule(Host, Access, From) of
|
|
deny ->
|
|
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
|
ejabberd_router:route(To, From, Err);
|
|
allow ->
|
|
announce_motd_update(Host, Packet)
|
|
end.
|
|
|
|
announce_motd_update(LServer, Packet) ->
|
|
announce_motd_delete(LServer),
|
|
F = fun() ->
|
|
mnesia:write(#motd{server = LServer, packet = Packet})
|
|
end,
|
|
mnesia:transaction(F).
|
|
|
|
announce_motd_delete(From, To, Packet) ->
|
|
Host = To#jid.lserver,
|
|
Access = gen_mod:get_module_opt(Host, ?MODULE, access, none),
|
|
case acl:match_rule(Host, Access, From) of
|
|
deny ->
|
|
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
|
|
ejabberd_router:route(To, From, Err);
|
|
allow ->
|
|
announce_motd_delete(Host)
|
|
end.
|
|
|
|
announce_motd_delete(LServer) ->
|
|
F = fun() ->
|
|
mnesia:delete({motd, LServer}),
|
|
mnesia:write_lock_table(motd_users),
|
|
Users = mnesia:select(
|
|
motd_users,
|
|
[{#motd_users{us = '$1', _ = '_'},
|
|
[{'==', {element, 2, '$1'}, LServer}],
|
|
['$1']}]),
|
|
lists:foreach(fun(US) ->
|
|
mnesia:delete({motd_users, US})
|
|
end, Users)
|
|
end,
|
|
mnesia:transaction(F).
|
|
|
|
send_motd(#jid{luser = LUser, lserver = LServer} = JID) ->
|
|
case catch mnesia:dirty_read({motd, LServer}) of
|
|
[#motd{packet = Packet}] ->
|
|
US = {LUser, LServer},
|
|
case catch mnesia:dirty_read({motd_users, US}) of
|
|
[#motd_users{}] ->
|
|
ok;
|
|
_ ->
|
|
Local = jlib:make_jid("", LServer, ""),
|
|
ejabberd_router:route(Local, JID, Packet),
|
|
F = fun() ->
|
|
mnesia:write(#motd_users{us = US})
|
|
end,
|
|
mnesia:transaction(F)
|
|
end;
|
|
_ ->
|
|
ok
|
|
end.
|
|
|
|
|
|
update_tables() ->
|
|
update_motd_table(),
|
|
update_motd_users_table().
|
|
|
|
update_motd_table() ->
|
|
Fields = record_info(fields, motd),
|
|
case mnesia:table_info(motd, attributes) of
|
|
Fields ->
|
|
ok;
|
|
[id, packet] ->
|
|
?INFO_MSG("Converting motd table from "
|
|
"{id, packet} format", []),
|
|
Host = ?MYNAME,
|
|
{atomic, ok} = mnesia:create_table(
|
|
mod_announce_tmp_table,
|
|
[{disc_only_copies, [node()]},
|
|
{type, bag},
|
|
{local_content, true},
|
|
{record_name, motd},
|
|
{attributes, record_info(fields, motd)}]),
|
|
mnesia:transform_table(motd, ignore, Fields),
|
|
F1 = fun() ->
|
|
mnesia:write_lock_table(mod_announce_tmp_table),
|
|
mnesia:foldl(
|
|
fun(#motd{server = _} = R, _) ->
|
|
mnesia:dirty_write(
|
|
mod_announce_tmp_table,
|
|
R#motd{server = Host})
|
|
end, ok, motd)
|
|
end,
|
|
mnesia:transaction(F1),
|
|
mnesia:clear_table(motd),
|
|
F2 = fun() ->
|
|
mnesia:write_lock_table(motd),
|
|
mnesia:foldl(
|
|
fun(R, _) ->
|
|
mnesia:dirty_write(R)
|
|
end, ok, mod_announce_tmp_table)
|
|
end,
|
|
mnesia:transaction(F2),
|
|
mnesia:delete_table(mod_announce_tmp_table);
|
|
_ ->
|
|
?INFO_MSG("Recreating motd table", []),
|
|
mnesia:transform_table(motd, ignore, Fields)
|
|
end.
|
|
|
|
|
|
update_motd_users_table() ->
|
|
Fields = record_info(fields, motd_users),
|
|
case mnesia:table_info(motd_users, attributes) of
|
|
Fields ->
|
|
ok;
|
|
[luser, dummy] ->
|
|
?INFO_MSG("Converting motd_users table from "
|
|
"{luser, dummy} format", []),
|
|
Host = ?MYNAME,
|
|
{atomic, ok} = mnesia:create_table(
|
|
mod_announce_tmp_table,
|
|
[{disc_only_copies, [node()]},
|
|
{type, bag},
|
|
{local_content, true},
|
|
{record_name, motd_users},
|
|
{attributes, record_info(fields, motd_users)}]),
|
|
mnesia:transform_table(motd_users, ignore, Fields),
|
|
F1 = fun() ->
|
|
mnesia:write_lock_table(mod_announce_tmp_table),
|
|
mnesia:foldl(
|
|
fun(#motd_users{us = U} = R, _) ->
|
|
mnesia:dirty_write(
|
|
mod_announce_tmp_table,
|
|
R#motd_users{us = {U, Host}})
|
|
end, ok, motd_users)
|
|
end,
|
|
mnesia:transaction(F1),
|
|
mnesia:clear_table(motd_users),
|
|
F2 = fun() ->
|
|
mnesia:write_lock_table(motd_users),
|
|
mnesia:foldl(
|
|
fun(R, _) ->
|
|
mnesia:dirty_write(R)
|
|
end, ok, mod_announce_tmp_table)
|
|
end,
|
|
mnesia:transaction(F2),
|
|
mnesia:delete_table(mod_announce_tmp_table);
|
|
_ ->
|
|
?INFO_MSG("Recreating motd_users table", []),
|
|
mnesia:transform_table(motd_users, ignore, Fields)
|
|
end.
|