aboutsummaryrefslogtreecommitdiff
path: root/src/mod_muc/mod_muc.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_muc/mod_muc.erl')
-rw-r--r--src/mod_muc/mod_muc.erl310
1 files changed, 238 insertions, 72 deletions
diff --git a/src/mod_muc/mod_muc.erl b/src/mod_muc/mod_muc.erl
index 049296f0e..1f40ca0a4 100644
--- a/src/mod_muc/mod_muc.erl
+++ b/src/mod_muc/mod_muc.erl
@@ -160,26 +160,70 @@ create_room(Host, Name, From, Nick, Opts) ->
Node = get_node({Name, RoomHost}),
gen_server:call({Proc, Node}, {create, Name, From, Nick, Opts}).
-store_room(_ServerHost, Host, Name, Opts) ->
+store_room(ServerHost, Host, Name, Opts) ->
+ LServer = jlib:nameprep(ServerHost),
+ store_room(LServer, Host, Name, Opts, gen_mod:db_type(LServer, ?MODULE)).
+
+store_room(_LServer, Host, Name, Opts, mnesia) ->
F = fun() ->
mnesia:write(#muc_room{name_host = {Name, Host},
opts = Opts})
end,
- mnesia:transaction(F).
+ mnesia:transaction(F);
+store_room(LServer, Host, Name, Opts, odbc) ->
+ SName = ejabberd_odbc:escape(Name),
+ SHost = ejabberd_odbc:escape(Host),
+ SOpts = ejabberd_odbc:encode_term(Opts),
+ F = fun() ->
+ odbc_queries:update_t(
+ "muc_room",
+ ["name", "host", "opts"],
+ [SName, SHost, SOpts],
+ ["name='", SName, "' and host='", SHost, "'"])
+ end,
+ ejabberd_odbc:sql_transaction(LServer, F).
-restore_room(_ServerHost, Host, Name) ->
+restore_room(ServerHost, Host, Name) ->
+ LServer = jlib:nameprep(ServerHost),
+ restore_room(LServer, Host, Name, gen_mod:db_type(LServer, ?MODULE)).
+
+restore_room(_LServer, Host, Name, mnesia) ->
case catch mnesia:dirty_read(muc_room, {Name, Host}) of
[#muc_room{opts = Opts}] ->
Opts;
_ ->
error
+ end;
+restore_room(LServer, Host, Name, odbc) ->
+ SName = ejabberd_odbc:escape(Name),
+ SHost = ejabberd_odbc:escape(Host),
+ case catch ejabberd_odbc:sql_query(
+ LServer, ["select opts from muc_room where name='",
+ SName, "' and host='", SHost, "';"]) of
+ {selected, ["opts"], [{Opts}]} ->
+ ejabberd_odbc:decode_term(Opts);
+ _ ->
+ error
end.
-forget_room(_ServerHost, Host, Name) ->
+forget_room(ServerHost, Host, Name) ->
+ LServer = jlib:nameprep(ServerHost),
+ forget_room(LServer, Host, Name, gen_mod:db_type(LServer, ?MODULE)).
+
+forget_room(_LServer, Host, Name, mnesia) ->
F = fun() ->
mnesia:delete({muc_room, {Name, Host}})
end,
- mnesia:transaction(F).
+ mnesia:transaction(F);
+forget_room(LServer, Host, Name, odbc) ->
+ SName = ejabberd_odbc:escape(Name),
+ SHost = ejabberd_odbc:escape(Host),
+ F = fun() ->
+ ejabberd_odbc:sql_query_t(
+ ["delete from muc_room where name='",
+ SName, "' and host='", SHost, "';"])
+ end,
+ ejabberd_odbc:sql_transaction(LServer, F).
process_iq_disco_items(Host, From, To, #iq{lang = Lang} = IQ) ->
Rsm = jlib:rsm_decode(IQ),
@@ -193,7 +237,11 @@ process_iq_disco_items(Host, From, To, #iq{lang = Lang} = IQ) ->
can_use_nick(_ServerHost, _Host, _JID, "") ->
false;
-can_use_nick(_ServerHost, Host, JID, Nick) ->
+can_use_nick(ServerHost, Host, JID, Nick) ->
+ LServer = jlib:nameprep(ServerHost),
+ can_use_nick(LServer, Host, JID, Nick, gen_mod:db_type(LServer, ?MODULE)).
+
+can_use_nick(_LServer, Host, JID, Nick, mnesia) ->
{LUser, LServer, _} = jlib:jid_tolower(JID),
LUS = {LUser, LServer},
case catch mnesia:dirty_select(
@@ -209,6 +257,21 @@ can_use_nick(_ServerHost, Host, JID, Nick) ->
true;
[#muc_registered{us_host = {U, _Host}}] ->
U == LUS
+ end;
+can_use_nick(LServer, Host, JID, Nick, odbc) ->
+ SJID = jlib:jid_to_string(
+ jlib:jid_tolower(
+ jlib:jid_remove_resource(JID))),
+ SNick = ejabberd_odbc:escape(Nick),
+ SHost = ejabberd_odbc:escape(Host),
+ case catch ejabberd_odbc:sql_query(
+ LServer, ["select jid from muc_registered ",
+ "where nick='", SNick, "' and host='",
+ SHost, "';"]) of
+ {selected, ["jid"], [{SJID1}]} ->
+ SJID == SJID1;
+ _ ->
+ true
end.
migrate(_Node, _UpOrDown, After) ->
@@ -263,22 +326,30 @@ copy_rooms(Key) ->
%% Description: Initiates the server
%%--------------------------------------------------------------------
init([Host, Opts]) ->
- update_muc_online_table(),
- mnesia:create_table(muc_room,
- [{disc_copies, [node()]},
- {attributes, record_info(fields, muc_room)}]),
- mnesia:create_table(muc_registered,
- [{disc_copies, [node()]},
- {attributes, record_info(fields, muc_registered)}]),
+ MyHost = gen_mod:get_opt_host(Host, Opts, "conference.@HOST@"),
+ case gen_mod:db_type(Opts) of
+ mnesia ->
+ update_muc_online_table(),
+ update_tables(MyHost),
+ mnesia:create_table(muc_room,
+ [{disc_copies, [node()]},
+ {attributes,
+ record_info(fields, muc_room)}]),
+ mnesia:create_table(muc_registered,
+ [{disc_copies, [node()]},
+ {attributes,
+ record_info(fields, muc_registered)}]),
+ mnesia:add_table_index(muc_registered, nick);
+ _ ->
+ ok
+ end,
mnesia:create_table(muc_online_room,
[{ram_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, muc_online_room)}]),
mnesia:add_table_copy(muc_online_room, node(), ram_copies),
catch ets:new(muc_online_users, [bag, named_table, public, {keypos, 2}]),
- MyHost = gen_mod:get_opt_host(Host, Opts, "conference.@HOST@"),
- update_tables(MyHost),
- mnesia:add_table_index(muc_registered, nick),
+ mnesia:subscribe(system),
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),
@@ -334,7 +405,7 @@ handle_call({create, Room, From, Nick, Opts},
Host, ServerHost, Access,
Room, HistorySize, PersistHistory,
RoomShaper, From,
- Nick, NewOpts, ?MODULE),
+ Nick, NewOpts),
register_room(Host, Room, Pid),
{reply, ok, State}.
@@ -491,7 +562,7 @@ do_route1(Host, ServerHost, Access, HistorySize, PersistHistory, RoomShaper,
[{xmlelement, "query",
[{"xmlns", XMLNS}],
iq_get_register_info(
- Host, From, Lang)}]},
+ ServerHost, Host, From, Lang)}]},
ejabberd_router:route(To,
From,
jlib:iq_to_xml(Res));
@@ -499,7 +570,8 @@ do_route1(Host, ServerHost, Access, HistorySize, PersistHistory, RoomShaper,
xmlns = ?NS_REGISTER = XMLNS,
lang = Lang,
sub_el = SubEl} = IQ ->
- case process_iq_register_set(Host, From, SubEl, Lang) of
+ case process_iq_register_set(
+ ServerHost, Host, From, SubEl, Lang) of
{result, IQRes} ->
Res = IQ#iq{type = result,
sub_el =
@@ -637,50 +709,72 @@ check_user_can_create_room(ServerHost, AccessCreate, From, RoomID) ->
false
end.
+get_rooms(ServerHost, Host) ->
+ LServer = jlib:nameprep(ServerHost),
+ get_rooms(LServer, Host, gen_mod:db_type(LServer, ?MODULE)).
-load_permanent_rooms(Host, ServerHost, Access, HistorySize, PersistHistory, RoomShaper) ->
+get_rooms(_LServer, Host, mnesia) ->
case catch mnesia:dirty_select(
muc_room, [{#muc_room{name_host = {'_', Host}, _ = '_'},
[],
['$_']}]) of
{'EXIT', Reason} ->
?ERROR_MSG("~p", [Reason]),
- ok;
+ [];
Rs ->
- lists:foreach(
- fun(R) ->
- {Room, Host} = R#muc_room.name_host,
- case get_node({Room, Host}) of
- Node when Node == node() ->
- case mnesia:dirty_read(muc_online_room, {Room, Host}) of
- [] ->
- case get_room_state_if_broadcasted(
- {Room, Host}) of
- {ok, RoomState} ->
- mod_muc_room:start(
- normal_state, RoomState);
- error ->
- {ok, Pid} = mod_muc_room:start(
- Host,
- ServerHost,
- Access,
- Room,
- HistorySize,
- PersistHistory,
- RoomShaper,
- R#muc_room.opts,
- ?MODULE),
- register_room(Host, Room, Pid)
- end;
- _ ->
- ok
- end;
- _ ->
- ok
- end
- end, Rs)
+ Rs
+ end;
+get_rooms(LServer, Host, odbc) ->
+ SHost = ejabberd_odbc:escape(Host),
+ case catch ejabberd_odbc:sql_query(
+ LServer, ["select name, opts from muc_room ",
+ "where host='", SHost, "';"]) of
+ {'EXIT', Reason} ->
+ ?ERROR_MSG("~p", [Reason]),
+ [];
+ {selected, ["name", "opts"], RoomOpts} ->
+ lists:map(
+ fun({Room, Opts}) ->
+ #muc_room{name_host = {Room, Host},
+ opts = ejabberd_odbc:decode_term(Opts)}
+ end, RoomOpts)
end.
+load_permanent_rooms(Host, ServerHost, Access, HistorySize, PersistHistory, RoomShaper) ->
+ lists:foreach(
+ fun(R) ->
+ {Room, Host} = R#muc_room.name_host,
+ case get_node({Room, Host}) of
+ Node when Node == node() ->
+ case mnesia:dirty_read(muc_online_room, {Room, Host}) of
+ [] ->
+ case get_room_state_if_broadcasted(
+ {Room, Host}) of
+ {ok, RoomState} ->
+ mod_muc_room:start(
+ normal_state, RoomState);
+ error ->
+ {ok, Pid} = mod_muc_room:start(
+ Host,
+ ServerHost,
+ Access,
+ Room,
+ HistorySize,
+ PersistHistory,
+ RoomShaper,
+ R#muc_room.opts),
+ register_room(Host, Room, Pid);
+ _ ->
+ ok
+ end;
+ _ ->
+ ok
+ end;
+ _ ->
+ ok
+ end
+ end, get_rooms(ServerHost, Host)).
+
start_new_room(Host, ServerHost, Access, Room,
HistorySize, PersistHistory, RoomShaper, From,
Nick, DefRoomOpts) ->
@@ -689,18 +783,18 @@ start_new_room(Host, ServerHost, Access, Room,
?DEBUG("MUC: restore room '~s' from other node~n", [Room]),
mod_muc_room:start(normal_state, RoomState);
error ->
- case mnesia:dirty_read(muc_room, {Room, Host}) of
- [] ->
+ case restore_room(ServerHost, Room, Host) of
+ error ->
?DEBUG("MUC: open new room '~s'~n", [Room]),
mod_muc_room:start(Host, ServerHost, Access,
Room, HistorySize, PersistHistory,
RoomShaper, From,
- Nick, DefRoomOpts, ?MODULE);
- [#muc_room{opts = Opts}|_] ->
+ Nick, DefRoomOpts);
+ Opts ->
?DEBUG("MUC: restore room '~s'~n", [Room]),
mod_muc_room:start(Host, ServerHost, Access,
Room, HistorySize, PersistHistory,
- RoomShaper, Opts, ?MODULE)
+ RoomShaper, Opts)
end
end.
@@ -861,18 +955,44 @@ flush() ->
iq_get_unique(From) ->
{xmlcdata, sha:sha(term_to_binary([From, now(), randoms:get_string()]))}.
-iq_get_register_info(Host, From, Lang) ->
+get_nick(ServerHost, Host, From) ->
+ LServer = jlib:nameprep(ServerHost),
+ get_nick(LServer, Host, From, gen_mod:db_type(LServer, ?MODULE)).
+
+get_nick(_LServer, Host, From, mnesia) ->
{LUser, LServer, _} = jlib:jid_tolower(From),
LUS = {LUser, LServer},
+ case catch mnesia:dirty_read(muc_registered, {LUS, Host}) of
+ {'EXIT', _Reason} ->
+ error;
+ [] ->
+ error;
+ [#muc_registered{nick = Nick}] ->
+ Nick
+ end;
+get_nick(LServer, Host, From, odbc) ->
+ SJID = ejabberd_odbc:escape(
+ jlib:jid_to_string(
+ jlib:jid_tolower(
+ jlib:jid_remove_resource(From)))),
+ SHost = ejabberd_odbc:escape(Host),
+ case catch ejabberd_odbc:sql_query(
+ LServer, ["select nick from muc_registered where "
+ "jid='", SJID, "' and host='", SHost, "';"]) of
+ {selected, ["nick"], [{Nick}]} ->
+ Nick;
+ _ ->
+ error
+ end.
+
+iq_get_register_info(ServerHost, Host, From, Lang) ->
{Nick, Registered} =
- case catch mnesia:dirty_read(muc_registered, {LUS, Host}) of
- {'EXIT', _Reason} ->
- {"", []};
- [] ->
- {"", []};
- [#muc_registered{nick = N}] ->
- {N, [{xmlelement, "registered", [], []}]}
- end,
+ case get_nick(ServerHost, Host, From) of
+ error ->
+ {"", []};
+ N ->
+ {N, [{xmlelement, "registered", [], []}]}
+ end,
Registered ++
[{xmlelement, "instructions", [],
[{xmlcdata,
@@ -890,7 +1010,11 @@ iq_get_register_info(Host, From, Lang) ->
Lang, "Enter nickname you want to register")}]},
?XFIELD("text-single", "Nickname", "nick", Nick)]}].
-iq_set_register_info(Host, From, Nick, Lang) ->
+set_nick(ServerHost, Host, From, Nick) ->
+ LServer = jlib:nameprep(ServerHost),
+ set_nick(LServer, Host, From, Nick, gen_mod:db_type(LServer, ?MODULE)).
+
+set_nick(_LServer, Host, From, Nick, mnesia) ->
{LUser, LServer, _} = jlib:jid_tolower(From),
LUS = {LUser, LServer},
F = fun() ->
@@ -923,7 +1047,48 @@ iq_set_register_info(Host, From, Nick, Lang) ->
end
end
end,
- case mnesia:transaction(F) of
+ mnesia:transaction(F);
+set_nick(LServer, Host, From, Nick, odbc) ->
+ JID = jlib:jid_to_string(
+ jlib:jid_tolower(
+ jlib:jid_remove_resource(From))),
+ SJID = ejabberd_odbc:escape(JID),
+ SNick = ejabberd_odbc:escape(Nick),
+ SHost = ejabberd_odbc:escape(Host),
+ F = fun() ->
+ case Nick of
+ "" ->
+ ejabberd_odbc:sql_query_t(
+ ["delete from muc_registered where ",
+ "jid='", SJID, "' and host='", Host, "';"]),
+ ok;
+ _ ->
+ Allow =
+ case ejabberd_odbc:sql_query_t(
+ ["select jid from muc_registered ",
+ "where nick='", SNick, "' and host='",
+ SHost, "';"]) of
+ {selected, ["jid"], [{J}]} ->
+ J == JID;
+ _ ->
+ true
+ end,
+ if Allow ->
+ odbc_queries:update_t(
+ "muc_registered",
+ ["jid", "host", "nick"],
+ [SJID, SHost, SNick],
+ ["jid='", SJID, "' and host='", SHost, "'"]),
+ ok;
+ true ->
+ false
+ end
+ end
+ end,
+ ejabberd_odbc:sql_transaction(LServer, F).
+
+iq_set_register_info(ServerHost, Host, From, Nick, Lang) ->
+ case set_nick(ServerHost, Host, From, Nick) of
{atomic, ok} ->
{result, []};
{atomic, false} ->
@@ -933,7 +1098,7 @@ iq_set_register_info(Host, From, Nick, Lang) ->
{error, ?ERR_INTERNAL_SERVER_ERROR}
end.
-process_iq_register_set(Host, From, SubEl, Lang) ->
+process_iq_register_set(ServerHost, Host, From, SubEl, Lang) ->
{xmlelement, _Name, _Attrs, Els} = SubEl,
case xml:get_subtag(SubEl, "remove") of
false ->
@@ -951,7 +1116,8 @@ process_iq_register_set(Host, From, SubEl, Lang) ->
_ ->
case lists:keysearch("nick", 1, XData) of
{value, {_, [Nick]}} when Nick /= "" ->
- iq_set_register_info(Host, From, Nick, Lang);
+ iq_set_register_info(ServerHost, Host,
+ From, Nick, Lang);
_ ->
ErrText = "You must fill in field \"Nickname\" in the form",
{error, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)}
@@ -964,7 +1130,7 @@ process_iq_register_set(Host, From, SubEl, Lang) ->
{error, ?ERR_BAD_REQUEST}
end;
_ ->
- iq_set_register_info(Host, From, "", Lang)
+ iq_set_register_info(ServerHost, Host, From, "", Lang)
end.
iq_get_vcard(Lang) ->