mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-20 16:15:59 +01:00
* src/mod_muc/: Support for more configuration options and
persistent rooms SVN Revision: 91
This commit is contained in:
parent
bc756c3737
commit
6d89957e06
@ -1,3 +1,8 @@
|
||||
2003-03-25 Alexey Shchepin <alexey@sevcom.net>
|
||||
|
||||
* src/mod_muc/: Support for more configuration options and
|
||||
persistent rooms
|
||||
|
||||
2003-03-23 Alexey Shchepin <alexey@sevcom.net>
|
||||
|
||||
* src/mod_muc/: MUC support (not completed yet)
|
||||
|
@ -15,7 +15,10 @@
|
||||
-export([start/1,
|
||||
init/1,
|
||||
stop/0,
|
||||
room_destroyed/1]).
|
||||
room_destroyed/1,
|
||||
store_room/2,
|
||||
restore_room/1,
|
||||
forget_room/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
@ -38,7 +41,7 @@ init(Host) ->
|
||||
public,
|
||||
{keypos, #muc_online_room.name}]),
|
||||
ejabberd_router:register_route(Host),
|
||||
% TODO: load permanent groups
|
||||
load_permanent_rooms(Host),
|
||||
loop(Host).
|
||||
|
||||
loop(Host) ->
|
||||
@ -136,7 +139,44 @@ iq_disco() ->
|
||||
[{"var", ?NS_MUC}], []}].
|
||||
|
||||
|
||||
store_room(Name, Opts) ->
|
||||
F = fun() ->
|
||||
mnesia:write(#muc_room{name = Name,
|
||||
opts = Opts})
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
||||
restore_room(Name) ->
|
||||
case catch mnesia:dirty_read(muc_room, Name) of
|
||||
[#muc_room{opts = Opts}] ->
|
||||
Opts;
|
||||
_ ->
|
||||
error
|
||||
end.
|
||||
|
||||
|
||||
forget_room(Name) ->
|
||||
F = fun() ->
|
||||
mnesia:delete({muc_room, Name})
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
||||
|
||||
load_permanent_rooms(Host) ->
|
||||
case catch mnesia:dirty_select(muc_room, [{'_', [], ['$_']}]) of
|
||||
{'EXIT', Reason} ->
|
||||
?ERROR_MSG("~p", [Reason]),
|
||||
ok;
|
||||
Rs ->
|
||||
lists:foreach(fun(R) ->
|
||||
Room = R#muc_room.name,
|
||||
{ok, Pid} = mod_muc_room:start(
|
||||
Host,
|
||||
Room,
|
||||
R#muc_room.opts),
|
||||
ets:insert(
|
||||
muc_online_room,
|
||||
#muc_online_room{name = Room, pid = Pid})
|
||||
end, Rs)
|
||||
end.
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
%% External exports
|
||||
-export([start/4,
|
||||
init/1,
|
||||
start/3,
|
||||
route/4]).
|
||||
|
||||
%% gen_fsm callbacks
|
||||
@ -35,6 +35,20 @@
|
||||
|
||||
-record(lqueue, {queue, len, max}).
|
||||
|
||||
-record(config, {allow_change_subj = true, % TODO
|
||||
allow_query_users = true,
|
||||
allow_private_messages = true,
|
||||
public = true, % TODO
|
||||
persistent = false, % TODO
|
||||
moderated = false, % TODO
|
||||
members_by_default = true, % TODO
|
||||
members_only = false, % TODO
|
||||
allow_user_invites = false, % TODO
|
||||
password_protected = false, % TODO
|
||||
anonymous = true, % TODO
|
||||
logging = false % TODO
|
||||
}).
|
||||
|
||||
-record(user, {jid,
|
||||
nick,
|
||||
role,
|
||||
@ -42,7 +56,7 @@
|
||||
|
||||
-record(state, {room,
|
||||
host,
|
||||
config,
|
||||
config = #config{},
|
||||
users = ?DICT:new(),
|
||||
affiliations = ?DICT:new(),
|
||||
history = lqueue_new(10),
|
||||
@ -78,6 +92,9 @@
|
||||
start(Host, Room, Creator, Nick) ->
|
||||
gen_fsm:start(?MODULE, [Host, Room, Creator, Nick], ?FSMOPTS).
|
||||
|
||||
start(Host, Room, Opts) ->
|
||||
gen_fsm:start(?MODULE, [Host, Room, Opts], ?FSMOPTS).
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Callback functions from gen_fsm
|
||||
%%%----------------------------------------------------------------------
|
||||
@ -94,6 +111,10 @@ init([Host, Room, Creator, Nick]) ->
|
||||
State = set_affiliation(Creator, owner,
|
||||
#state{host = Host,
|
||||
room = Room}),
|
||||
{ok, normal_state, State};
|
||||
init([Host, Room, Opts]) ->
|
||||
State = set_opts(Opts, #state{host = Host,
|
||||
room = Room}),
|
||||
{ok, normal_state, State}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
@ -186,14 +207,21 @@ normal_state({route, From, "",
|
||||
{xmlelement, "iq", Attrs, Els} = Packet},
|
||||
StateData) ->
|
||||
case jlib:iq_query_info(Packet) of
|
||||
{iq, ID, Type, ?NS_MUC_ADMIN = XMLNS, SubEl} ->
|
||||
{iq, ID, Type, XMLNS, SubEl} when
|
||||
(XMLNS == ?NS_MUC_ADMIN) or (XMLNS == ?NS_MUC_OWNER) ->
|
||||
Res1 = case XMLNS of
|
||||
?NS_MUC_ADMIN ->
|
||||
process_iq_admin(From, Type, SubEl, StateData);
|
||||
?NS_MUC_OWNER ->
|
||||
process_iq_owner(From, Type, SubEl, StateData)
|
||||
end,
|
||||
{IQRes, NewStateData} =
|
||||
case process_iq_admin(From, Type, SubEl, StateData) of
|
||||
case Res1 of
|
||||
{result, Res, SD} ->
|
||||
{{iq, ID, result, XMLNS,
|
||||
[{xmlelement, "query", [{"xmlns", XMLNS}],
|
||||
Res
|
||||
}]},
|
||||
}]},
|
||||
SD};
|
||||
{error, Error} ->
|
||||
{{iq, ID, error, XMLNS,
|
||||
@ -314,7 +342,8 @@ normal_state({route, From, Nick,
|
||||
normal_state({route, From, ToNick,
|
||||
{xmlelement, "message", Attrs, Els} = Packet},
|
||||
StateData) ->
|
||||
case is_user_online(From, StateData) of
|
||||
case (StateData#state.config)#config.allow_private_messages
|
||||
andalso is_user_online(From, StateData) of
|
||||
true ->
|
||||
case find_jid_by_nick(ToNick, StateData) of
|
||||
false ->
|
||||
@ -342,10 +371,30 @@ normal_state({route, From, ToNick,
|
||||
normal_state({route, From, ToNick,
|
||||
{xmlelement, "iq", Attrs, Els} = Packet},
|
||||
StateData) ->
|
||||
Err = jlib:make_error_reply(
|
||||
Packet, ?ERR_FEATURE_NOT_IMPLEMENTED),
|
||||
ejabberd_router:route(
|
||||
{StateData#state.room, StateData#state.host, ToNick}, From, Err),
|
||||
case (StateData#state.config)#config.allow_query_users
|
||||
andalso is_user_online(From, StateData) of
|
||||
true ->
|
||||
case find_jid_by_nick(ToNick, StateData) of
|
||||
false ->
|
||||
Err = jlib:make_error_reply(
|
||||
Packet, ?ERR_JID_NOT_FOUND),
|
||||
ejabberd_router:route(
|
||||
{StateData#state.room, StateData#state.host, ToNick},
|
||||
From, Err);
|
||||
ToJID ->
|
||||
{ok, #user{nick = FromNick}} =
|
||||
?DICT:find(jlib:jid_tolower(From),
|
||||
StateData#state.users),
|
||||
ejabberd_router:route(
|
||||
{StateData#state.room, StateData#state.host, FromNick},
|
||||
ToJID, Packet)
|
||||
end;
|
||||
_ ->
|
||||
Err = jlib:make_error_reply(
|
||||
Packet, ?ERR_NOT_ALLOWED),
|
||||
ejabberd_router:route(
|
||||
{StateData#state.room, StateData#state.host, ToNick}, From, Err)
|
||||
end,
|
||||
{next_state, normal_state, StateData};
|
||||
|
||||
normal_state(Event, StateData) ->
|
||||
@ -501,7 +550,13 @@ get_default_role(Affiliation, StateData) ->
|
||||
admin -> moderator;
|
||||
member -> participant;
|
||||
outcast -> none;
|
||||
none -> participant
|
||||
none ->
|
||||
case (StateData#state.config)#config.members_by_default of
|
||||
true ->
|
||||
participant;
|
||||
_ ->
|
||||
visitor
|
||||
end
|
||||
end.
|
||||
|
||||
|
||||
@ -1184,4 +1239,265 @@ send_kickban_presence(UJID, Code, StateData) ->
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% Owner stuff
|
||||
|
||||
process_iq_owner(From, set, SubEl, StateData) ->
|
||||
FAffiliation = get_affiliation(From, StateData),
|
||||
case FAffiliation of
|
||||
owner ->
|
||||
{xmlelement, Name, Attrs, Els} = SubEl,
|
||||
Lang = xml:get_tag_attr_s("xml:lang", SubEl),
|
||||
case xml:remove_cdata(Els) of
|
||||
[{xmlelement, "x", Attrs1, Els1} = XEl] ->
|
||||
case {xml:get_tag_attr_s("xmlns", XEl),
|
||||
xml:get_tag_attr_s("type", XEl)} of
|
||||
{?NS_XDATA, "cancel"} ->
|
||||
{error, ?ERR_FEATURE_NOT_IMPLEMENTED};
|
||||
{?NS_XDATA, "submit"} ->
|
||||
set_config(XEl, StateData);
|
||||
_ ->
|
||||
{error, ?ERR_BAD_REQUEST}
|
||||
end;
|
||||
_ ->
|
||||
{error, ?ERR_FEATURE_NOT_IMPLEMENTED}
|
||||
end;
|
||||
_ ->
|
||||
{error, ?ERR_NOT_ALLOWED}
|
||||
end;
|
||||
% {xmlelement, _, _, Items} = SubEl,
|
||||
% process_admin_items_set(From, Items, StateData);
|
||||
% {error, ?ERR_FEATURE_NOT_IMPLEMENTED};
|
||||
|
||||
process_iq_owner(From, get, SubEl, StateData) ->
|
||||
FAffiliation = get_affiliation(From, StateData),
|
||||
case FAffiliation of
|
||||
owner ->
|
||||
{xmlelement, Name, Attrs, Els} = SubEl,
|
||||
Lang = xml:get_tag_attr_s("xml:lang", SubEl),
|
||||
case xml:remove_cdata(Els) of
|
||||
[] ->
|
||||
get_config(Lang, StateData);
|
||||
_ ->
|
||||
{error, ?ERR_FEATURE_NOT_IMPLEMENTED}
|
||||
end;
|
||||
_ ->
|
||||
{error, ?ERR_NOT_ALLOWED}
|
||||
end.
|
||||
|
||||
|
||||
% case xml:get_subtag(SubEl, "item") of
|
||||
% false ->
|
||||
% {error, ?ERR_BAD_REQUEST};
|
||||
% Item ->
|
||||
% FAffiliation = get_affiliation(From, StateData),
|
||||
% FRole = get_role(From, StateData),
|
||||
% case xml:get_tag_attr("role", Item) of
|
||||
% false ->
|
||||
% case xml:get_tag_attr("affiliation", Item) of
|
||||
% false ->
|
||||
% {error, ?ERR_BAD_REQUEST};
|
||||
% {value, StrAffiliation} ->
|
||||
% case catch list_to_affiliation(StrAffiliation) of
|
||||
% {'EXIT', _} ->
|
||||
% {error, ?ERR_BAD_REQUEST};
|
||||
% SAffiliation ->
|
||||
% if
|
||||
% FAffiliation == owner ->
|
||||
% Items = items_with_affiliation(
|
||||
% SAffiliation, StateData),
|
||||
% {result, Items, StateData};
|
||||
% true ->
|
||||
% {error, ?ERR_NOT_ALLOWED}
|
||||
% end
|
||||
% end
|
||||
% end;
|
||||
% {value, StrRole} ->
|
||||
% case catch list_to_role(StrRole) of
|
||||
% {'EXIT', _} ->
|
||||
% {error, ?ERR_BAD_REQUEST};
|
||||
% SRole ->
|
||||
% if
|
||||
% FAffiliation == owner ->
|
||||
% Items = items_with_role(SRole, StateData),
|
||||
% {result, Items, StateData};
|
||||
% true ->
|
||||
% {error, ?ERR_NOT_ALLOWED}
|
||||
% end
|
||||
% end
|
||||
% end
|
||||
% end.
|
||||
|
||||
|
||||
-define(XFIELD(Type, Label, Var, Val),
|
||||
{xmlelement, "field", [{"type", Type},
|
||||
{"label", translate:translate(Lang, Label)},
|
||||
{"var", Var}],
|
||||
[{xmlelement, "value", [], [{xmlcdata, Val}]}]}).
|
||||
|
||||
-define(BOOLXFIELD(Label, Var, Val),
|
||||
?XFIELD("boolean", Label, Var,
|
||||
case Val of
|
||||
true -> "1";
|
||||
_ -> "0"
|
||||
end)).
|
||||
|
||||
|
||||
get_config(Lang, StateData) ->
|
||||
Config = StateData#state.config,
|
||||
Res =
|
||||
[?BOOLXFIELD("Allow users to change subject?",
|
||||
"allow_change_subj",
|
||||
Config#config.allow_change_subj),
|
||||
?BOOLXFIELD("Allow users to query other users?",
|
||||
"allow_query_users",
|
||||
Config#config.allow_query_users),
|
||||
?BOOLXFIELD("Allow users to send private messages?",
|
||||
"allow_private_messages",
|
||||
Config#config.allow_private_messages),
|
||||
?BOOLXFIELD("Make room public searchable?",
|
||||
"public",
|
||||
Config#config.public),
|
||||
?BOOLXFIELD("Make room persistent?",
|
||||
"persistent",
|
||||
Config#config.persistent),
|
||||
?BOOLXFIELD("Make room moderated?",
|
||||
"moderated",
|
||||
Config#config.moderated),
|
||||
?BOOLXFIELD("Default users as members?",
|
||||
"members_by_default",
|
||||
Config#config.members_by_default),
|
||||
?BOOLXFIELD("Make room members only?",
|
||||
"members_only",
|
||||
Config#config.members_only),
|
||||
?BOOLXFIELD("Allow users to send invites?",
|
||||
"allow_user_invites",
|
||||
Config#config.allow_user_invites),
|
||||
?BOOLXFIELD("Make room password protected?",
|
||||
"password_protected",
|
||||
Config#config.password_protected),
|
||||
?BOOLXFIELD("Make room anonymous?",
|
||||
"anonymous",
|
||||
Config#config.anonymous),
|
||||
?BOOLXFIELD("Enable logging?",
|
||||
"logging",
|
||||
Config#config.logging)
|
||||
],
|
||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}], Res}], StateData}.
|
||||
|
||||
|
||||
|
||||
set_config(XEl, StateData) ->
|
||||
XData = jlib:parse_xdata_submit(XEl),
|
||||
case XData of
|
||||
invalid ->
|
||||
{error, ?ERR_BAD_REQUEST};
|
||||
_ ->
|
||||
case set_xoption(XData, StateData#state.config) of
|
||||
#config{} = Config ->
|
||||
change_config(Config, StateData);
|
||||
Err ->
|
||||
Err
|
||||
end
|
||||
end.
|
||||
|
||||
-define(SET_BOOL_XOPT(Opt, Val),
|
||||
case Val of
|
||||
"0" -> set_xoption(Opts, Config#config{Opt = false});
|
||||
"1" -> set_xoption(Opts, Config#config{Opt = true});
|
||||
_ -> {error, ?ERR_BAD_REQUEST}
|
||||
end).
|
||||
|
||||
|
||||
|
||||
set_xoption([], Config) ->
|
||||
Config;
|
||||
set_xoption([{"allow_change_subj", [Val]} | Opts], Config) ->
|
||||
?SET_BOOL_XOPT(allow_change_subj, Val);
|
||||
set_xoption([{"allow_query_users", [Val]} | Opts], Config) ->
|
||||
?SET_BOOL_XOPT(allow_query_users, Val);
|
||||
set_xoption([{"allow_private_messages", [Val]} | Opts], Config) ->
|
||||
?SET_BOOL_XOPT(allow_private_messages, Val);
|
||||
set_xoption([{"public", [Val]} | Opts], Config) ->
|
||||
?SET_BOOL_XOPT(public, Val);
|
||||
set_xoption([{"persistent", [Val]} | Opts], Config) ->
|
||||
?SET_BOOL_XOPT(persistent, Val);
|
||||
set_xoption([{"moderated", [Val]} | Opts], Config) ->
|
||||
?SET_BOOL_XOPT(moderated, Val);
|
||||
set_xoption([{"members_by_default", [Val]} | Opts], Config) ->
|
||||
?SET_BOOL_XOPT(members_by_default, Val);
|
||||
set_xoption([{"members_only", [Val]} | Opts], Config) ->
|
||||
?SET_BOOL_XOPT(members_only, Val);
|
||||
set_xoption([{"allow_user_invites", [Val]} | Opts], Config) ->
|
||||
?SET_BOOL_XOPT(allow_user_invites, Val);
|
||||
set_xoption([{"password_protected", [Val]} | Opts], Config) ->
|
||||
?SET_BOOL_XOPT(password_protected, Val);
|
||||
set_xoption([{"anonymous", [Val]} | Opts], Config) ->
|
||||
?SET_BOOL_XOPT(anonymous, Val);
|
||||
set_xoption([{"logging", [Val]} | Opts], Config) ->
|
||||
?SET_BOOL_XOPT(logging, Val);
|
||||
set_xoption([_ | Opts], Config) ->
|
||||
{error, ?ERR_BAD_REQUEST}.
|
||||
|
||||
|
||||
change_config(Config, StateData) ->
|
||||
NSD = StateData#state{config = Config},
|
||||
case {(StateData#state.config)#config.persistent,
|
||||
Config#config.persistent} of
|
||||
{_, true} ->
|
||||
mod_muc:store_room(NSD#state.room, make_opts(NSD));
|
||||
{true, false} ->
|
||||
mod_muc:forget_room(NSD#state.room);
|
||||
{false, false} ->
|
||||
ok
|
||||
end,
|
||||
{result, [], NSD}.
|
||||
|
||||
|
||||
-define(CASE_CONFIG_OPT(Opt),
|
||||
Opt -> StateData#state{
|
||||
config = (StateData#state.config)#config{Opt = Val}}).
|
||||
|
||||
set_opts([], StateData) ->
|
||||
StateData;
|
||||
set_opts([{Opt, Val} | Opts], StateData) ->
|
||||
NSD = case Opt of
|
||||
?CASE_CONFIG_OPT(allow_change_subj);
|
||||
?CASE_CONFIG_OPT(allow_query_users);
|
||||
?CASE_CONFIG_OPT(allow_private_messages);
|
||||
?CASE_CONFIG_OPT(public);
|
||||
?CASE_CONFIG_OPT(persistent);
|
||||
?CASE_CONFIG_OPT(moderated);
|
||||
?CASE_CONFIG_OPT(members_by_default);
|
||||
?CASE_CONFIG_OPT(members_only);
|
||||
?CASE_CONFIG_OPT(allow_user_invites);
|
||||
?CASE_CONFIG_OPT(password_protected);
|
||||
?CASE_CONFIG_OPT(anonymous);
|
||||
?CASE_CONFIG_OPT(logging);
|
||||
affiliations ->
|
||||
StateData#state{affiliations = ?DICT:from_list(Val)};
|
||||
_ -> StateData
|
||||
end,
|
||||
set_opts(Opts, NSD).
|
||||
|
||||
-define(MAKE_CONFIG_OPT(Opt), {Opt, Config#config.Opt}).
|
||||
|
||||
make_opts(StateData) ->
|
||||
Config = StateData#state.config,
|
||||
[
|
||||
?MAKE_CONFIG_OPT(allow_change_subj),
|
||||
?MAKE_CONFIG_OPT(allow_query_users),
|
||||
?MAKE_CONFIG_OPT(allow_private_messages),
|
||||
?MAKE_CONFIG_OPT(public),
|
||||
?MAKE_CONFIG_OPT(persistent),
|
||||
?MAKE_CONFIG_OPT(moderated),
|
||||
?MAKE_CONFIG_OPT(members_by_default),
|
||||
?MAKE_CONFIG_OPT(members_only),
|
||||
?MAKE_CONFIG_OPT(allow_user_invites),
|
||||
?MAKE_CONFIG_OPT(password_protected),
|
||||
?MAKE_CONFIG_OPT(anonymous),
|
||||
?MAKE_CONFIG_OPT(logging),
|
||||
{affiliations, ?DICT:to_list(StateData#state.affiliations)}
|
||||
].
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user