summaryrefslogtreecommitdiff
path: root/src/mod_muc
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_muc')
-rw-r--r--src/mod_muc/mod_muc.erl284
-rw-r--r--src/mod_muc/mod_muc_room.erl20
2 files changed, 206 insertions, 98 deletions
diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl
index b3112472..742565a6 100644
--- a/src/mod_muc/mod_muc.erl
+++ b/src/mod_muc/mod_muc.erl
@@ -10,10 +10,12 @@
-author('alexey@sevcom.net').
-vsn('$Revision$ ').
+-behaviour(gen_server).
-behaviour(gen_mod).
--export([start/2,
- init/3,
+%% API
+-export([start_link/2,
+ start/2,
stop/1,
room_destroyed/3,
store_room/3,
@@ -22,6 +24,10 @@
process_iq_disco_items/4,
can_use_nick/3]).
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
-include("ejabberd.hrl").
-include("jlib.hrl").
@@ -30,9 +36,106 @@
-record(muc_online_room, {name_host, pid}).
-record(muc_registered, {us_host, nick}).
+-record(state, {host, server_host, access}).
+
-define(PROCNAME, ejabberd_mod_muc).
+%%====================================================================
+%% API
+%%====================================================================
+%%--------------------------------------------------------------------
+%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
+%% Description: Starts the server
+%%--------------------------------------------------------------------
+start_link(Host, Opts) ->
+ Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
+ gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
+
start(Host, Opts) ->
+ start_supervisor(Host),
+ Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
+ ChildSpec =
+ {Proc,
+ {?MODULE, start_link, [Host, Opts]},
+ temporary,
+ 1000,
+ worker,
+ [?MODULE]},
+ supervisor:start_child(ejabberd_sup, ChildSpec).
+
+stop(Host) ->
+ stop_supervisor(Host),
+ Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
+ gen_server:call(Proc, stop),
+ supervisor:delete_child(ejabberd_sup, Proc).
+
+room_destroyed(Host, Room, ServerHost) ->
+ gen_mod:get_module_proc(ServerHost, ?PROCNAME) !
+ {room_destroyed, {Room, Host}},
+ ok.
+
+store_room(Host, Name, Opts) ->
+ F = fun() ->
+ mnesia:write(#muc_room{name_host = {Name, Host},
+ opts = Opts})
+ end,
+ mnesia:transaction(F).
+
+restore_room(Host, Name) ->
+ case catch mnesia:dirty_read(muc_room, {Name, Host}) of
+ [#muc_room{opts = Opts}] ->
+ Opts;
+ _ ->
+ error
+ end.
+
+forget_room(Host, Name) ->
+ F = fun() ->
+ mnesia:delete({muc_room, {Name, Host}})
+ end,
+ mnesia:transaction(F).
+
+process_iq_disco_items(Host, From, To, #iq{lang = Lang} = IQ) ->
+ Res = IQ#iq{type = result,
+ sub_el = [{xmlelement, "query",
+ [{"xmlns", ?NS_DISCO_ITEMS}],
+ iq_disco_items(Host, From, Lang)}]},
+ ejabberd_router:route(To,
+ From,
+ jlib:iq_to_xml(Res)).
+
+can_use_nick(_Host, _JID, "") ->
+ false;
+can_use_nick(Host, JID, Nick) ->
+ {LUser, LServer, _} = jlib:jid_tolower(JID),
+ LUS = {LUser, LServer},
+ case catch mnesia:dirty_select(
+ muc_registered,
+ [{#muc_registered{us_host = '$1',
+ nick = Nick,
+ _ = '_'},
+ [{'==', {element, 2, '$1'}, Host}],
+ ['$_']}]) of
+ {'EXIT', _Reason} ->
+ true;
+ [] ->
+ true;
+ [#muc_registered{us_host = {U, _Host}}] ->
+ U == LUS
+ end.
+
+%%====================================================================
+%% gen_server callbacks
+%%====================================================================
+
+%%--------------------------------------------------------------------
+%% Function: init(Args) -> {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%% Description: Initiates the server
+%%--------------------------------------------------------------------
+init([Host, Opts]) ->
mnesia:create_table(muc_room,
[{disc_copies, [node()]},
{attributes, record_info(fields, muc_room)}]),
@@ -45,40 +148,96 @@ start(Host, Opts) ->
Access = gen_mod:get_opt(access, Opts, all),
AccessCreate = gen_mod:get_opt(access_create, Opts, all),
AccessAdmin = gen_mod:get_opt(access_admin, Opts, none),
- register(gen_mod:get_module_proc(Host, ?PROCNAME),
- spawn(?MODULE, init,
- [MyHost, Host, {Access, AccessCreate, AccessAdmin}])).
-
-
-
-init(Host, ServerHost, Access) ->
catch ets:new(muc_online_room, [named_table,
public,
{keypos, #muc_online_room.name_host}]),
- ejabberd_router:register_route(Host),
- load_permanent_rooms(Host, ServerHost, Access),
- loop(Host, ServerHost, Access).
-
-loop(Host, ServerHost, Access) ->
- receive
- {route, From, To, Packet} ->
- case catch do_route(Host, ServerHost, Access, From, To, Packet) of
- {'EXIT', Reason} ->
- ?ERROR_MSG("~p", [Reason]);
- _ ->
- ok
- end,
- loop(Host, ServerHost, Access);
- {room_destroyed, RoomHost} ->
- ets:delete(muc_online_room, RoomHost),
- loop(Host, ServerHost, Access);
- stop ->
- ejabberd_router:unregister_route(Host),
- ok;
+ ejabberd_router:register_route(MyHost),
+ load_permanent_rooms(MyHost, Host, {Access, AccessCreate, AccessAdmin}),
+ {ok, #state{host = MyHost,
+ server_host = Host,
+ access = {Access, AccessCreate, AccessAdmin}}}.
+
+%%--------------------------------------------------------------------
+%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} |
+%% {stop, Reason, State}
+%% Description: Handling call messages
+%%--------------------------------------------------------------------
+handle_call(stop, _From, State) ->
+ {stop, normal, ok, State}.
+
+%%--------------------------------------------------------------------
+%% Function: handle_cast(Msg, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% Description: Handling cast messages
+%%--------------------------------------------------------------------
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: handle_info(Info, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% Description: Handling all non call/cast messages
+%%--------------------------------------------------------------------
+handle_info({route, From, To, Packet},
+ #state{host = Host,
+ server_host = ServerHost,
+ access = Access} = State) ->
+ case catch do_route(Host, ServerHost, Access, From, To, Packet) of
+ {'EXIT', Reason} ->
+ ?ERROR_MSG("~p", [Reason]);
_ ->
- loop(Host, ServerHost, Access)
- end.
+ ok
+ end,
+ {noreply, State};
+handle_info({room_destroyed, RoomHost}, State) ->
+ ets:delete(muc_online_room, RoomHost),
+ {noreply, State};
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: terminate(Reason, State) -> void()
+%% Description: This function is called by a gen_server when it is about to
+%% terminate. It should be the opposite of Module:init/1 and do any necessary
+%% cleaning up. When it returns, the gen_server terminates with Reason.
+%% The return value is ignored.
+%%--------------------------------------------------------------------
+terminate(_Reason, State) ->
+ ejabberd_router:unregister_route(State#state.host),
+ ok.
+%%--------------------------------------------------------------------
+%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
+%% Description: Convert process state when code is changed
+%%--------------------------------------------------------------------
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+start_supervisor(Host) ->
+ Proc = gen_mod:get_module_proc(Host, ejabberd_mod_muc_sup),
+ ChildSpec =
+ {Proc,
+ {ejabberd_tmp_sup, start_link,
+ [Proc, mod_muc_room]},
+ permanent,
+ infinity,
+ supervisor,
+ [ejabberd_tmp_sup]},
+ supervisor:start_child(ejabberd_sup, ChildSpec).
+
+stop_supervisor(Host) ->
+ Proc = gen_mod:get_module_proc(Host, ejabberd_mod_muc_sup),
+ supervisor:terminate_child(ejabberd_sup, Proc),
+ supervisor:delete_child(ejabberd_sup, Proc).
do_route(Host, ServerHost, Access, From, To, Packet) ->
{AccessRoute, _AccessCreate, _AccessAdmin} = Access,
@@ -252,40 +411,6 @@ do_route1(Host, ServerHost, Access, From, To, Packet) ->
-room_destroyed(Host, Room, ServerHost) ->
- gen_mod:get_module_proc(ServerHost, ?PROCNAME) !
- {room_destroyed, {Room, Host}},
- ok.
-
-stop(Host) ->
- Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
- Proc ! stop,
- {wait, Proc}.
-
-
-store_room(Host, Name, Opts) ->
- F = fun() ->
- mnesia:write(#muc_room{name_host = {Name, Host},
- opts = Opts})
- end,
- mnesia:transaction(F).
-
-restore_room(Host, Name) ->
- case catch mnesia:dirty_read(muc_room, {Name, Host}) of
- [#muc_room{opts = Opts}] ->
- Opts;
- _ ->
- error
- end.
-
-
-forget_room(Host, Name) ->
- F = fun() ->
- mnesia:delete({muc_room, {Name, Host}})
- end,
- mnesia:transaction(F).
-
-
load_permanent_rooms(Host, ServerHost, Access) ->
case catch mnesia:dirty_select(
muc_room, [{#muc_room{name_host = {'_', Host}, _ = '_'},
@@ -321,15 +446,6 @@ iq_disco_info() ->
{xmlelement, "feature", [{"var", ?NS_VCARD}], []}].
-process_iq_disco_items(Host, From, To, #iq{lang = Lang} = IQ) ->
- Res = IQ#iq{type = result,
- sub_el = [{xmlelement, "query",
- [{"xmlns", ?NS_DISCO_ITEMS}],
- iq_disco_items(Host, From, Lang)}]},
- ejabberd_router:route(To,
- From,
- jlib:iq_to_xml(Res)).
-
iq_disco_items(Host, From, Lang) ->
lists:zf(fun(#muc_online_room{name_host = {Name, _Host}, pid = Pid}) ->
case catch gen_fsm:sync_send_all_state_event(
@@ -482,26 +598,6 @@ get_vh_rooms(Host) ->
['$_']}]).
-can_use_nick(_Host, _JID, "") ->
- false;
-can_use_nick(Host, JID, Nick) ->
- {LUser, LServer, _} = jlib:jid_tolower(JID),
- LUS = {LUser, LServer},
- case catch mnesia:dirty_select(
- muc_registered,
- [{#muc_registered{us_host = '$1',
- nick = Nick,
- _ = '_'},
- [{'==', {element, 2, '$1'}, Host}],
- ['$_']}]) of
- {'EXIT', _Reason} ->
- true;
- [] ->
- true;
- [#muc_registered{us_host = {U, _Host}}] ->
- U == LUS
- end.
-
update_tables(Host) ->
update_muc_room_table(Host),
diff --git a/src/mod_muc/mod_muc_room.erl b/src/mod_muc/mod_muc_room.erl
index 9cbdc687..8942b832 100644
--- a/src/mod_muc/mod_muc_room.erl
+++ b/src/mod_muc/mod_muc_room.erl
@@ -14,7 +14,9 @@
%% External exports
--export([start/6,
+-export([start_link/6,
+ start_link/5,
+ start/6,
start/5,
route/4]).
@@ -84,11 +86,21 @@
%%% API
%%%----------------------------------------------------------------------
start(Host, ServerHost, Access, Room, Creator, Nick) ->
- gen_fsm:start(?MODULE, [Host, ServerHost, Access, Room, Creator, Nick],
- ?FSMOPTS).
+ Supervisor = gen_mod:get_module_proc(ServerHost, ejabberd_mod_muc_sup),
+ supervisor:start_child(
+ Supervisor, [Host, ServerHost, Access, Room, Creator, Nick]).
start(Host, ServerHost, Access, Room, Opts) ->
- gen_fsm:start(?MODULE, [Host, ServerHost, Access, Room, Opts], ?FSMOPTS).
+ Supervisor = gen_mod:get_module_proc(ServerHost, ejabberd_mod_muc_sup),
+ supervisor:start_child(
+ Supervisor, [Host, ServerHost, Access, Room, Opts]).
+
+start_link(Host, ServerHost, Access, Room, Creator, Nick) ->
+ gen_fsm:start_link(?MODULE, [Host, ServerHost, Access, Room, Creator, Nick],
+ ?FSMOPTS).
+
+start_link(Host, ServerHost, Access, Room, Opts) ->
+ gen_fsm:start_link(?MODULE, [Host, ServerHost, Access, Room, Opts], ?FSMOPTS).
%%%----------------------------------------------------------------------
%%% Callback functions from gen_fsm