Add commands for MUC subscriptions management

This commit is contained in:
Evgeniy Khramtsov 2016-08-09 13:36:43 +03:00
parent c4b14d045a
commit 1fc58ace2f
2 changed files with 144 additions and 1 deletions

View File

@ -20,6 +20,7 @@
change_room_option/4, get_room_options/2,
set_room_affiliation/4, get_room_affiliations/2,
web_menu_main/2, web_page_main/2, web_menu_host/3,
subscribe_room/4, unsubscribe_room/2,
web_page_host/3, mod_opt_type/1, get_commands_spec/0]).
-include("ejabberd.hrl").
@ -151,7 +152,17 @@ get_commands_spec() ->
{value, string}
]}}
}}},
#ejabberd_commands{name = subscribe_room, tags = [muc_room],
desc = "Subscribe to a MUC conference",
module = ?MODULE, function = subscribe_room,
args = [{user, binary}, {nick, binary}, {room, binary},
{nodes, binary}],
result = {list, {node, string}}},
#ejabberd_commands{name = unsubscribe_room, tags = [muc_room],
desc = "Unsubscribe from a MUC conference",
module = ?MODULE, function = unsubscribe_room,
args = [{user, binary}, {room, binary}],
result = {res, rescode}},
#ejabberd_commands{name = set_room_affiliation, tags = [muc_room],
desc = "Change an affiliation in a MUC room",
module = ?MODULE, function = set_room_affiliation,
@ -884,6 +895,64 @@ set_room_affiliation(Name, Service, JID, AffiliationString) ->
error
end.
%%%
%%% MUC Subscription
%%%
subscribe_room(_User, Nick, _Room, _Nodes) when Nick == <<"">> ->
throw({error, "Nickname must be set"});
subscribe_room(User, Nick, Room, Nodes) ->
NodeList = re:split(Nodes, "\\h*,\\h*"),
case jid:from_string(Room) of
#jid{luser = Name, lserver = Host} when Name /= <<"">> ->
case jid:from_string(User) of
error ->
throw({error, "Malformed user JID"});
JID ->
UserJID = jid:replace_resource(JID, Nick),
case get_room_pid(Name, Host) of
Pid when is_pid(Pid) ->
case gen_fsm:sync_send_all_state_event(
Pid,
{muc_subscribe, UserJID, Nick, NodeList}) of
{ok, SubscribedNodes} ->
SubscribedNodes;
{error, Reason} ->
throw({error, binary_to_list(Reason)})
end;
_ ->
throw({error, "The room does not exist"})
end
end;
_ ->
throw({error, "Malformed room JID"})
end.
unsubscribe_room(User, Room) ->
case jid:from_string(Room) of
#jid{luser = Name, lserver = Host} when Name /= <<"">> ->
case jid:from_string(User) of
error ->
throw({error, "Malformed user JID"});
UserJID ->
case get_room_pid(Name, Host) of
Pid when is_pid(Pid) ->
case gen_fsm:sync_send_all_state_event(
Pid,
{muc_unsubscribe, UserJID}) of
ok ->
ok;
{error, Reason} ->
throw({error, binary_to_list(Reason)})
end;
_ ->
throw({error, "The room does not exist"})
end
end;
_ ->
throw({error, "Malformed room JID"})
end.
make_opts(StateData) ->
Config = StateData#state.config,
[

View File

@ -749,6 +749,60 @@ handle_sync_event({change_state, NewStateData}, _From,
handle_sync_event({process_item_change, Item, UJID}, _From, StateName, StateData) ->
NSD = process_item_change(Item, StateData, UJID),
{reply, {ok, NSD}, StateName, NSD};
handle_sync_event({muc_subscribe, From, Nick, Nodes}, _From,
StateName, StateData) ->
SubEl = #xmlel{name = <<"subscribe">>,
attrs = [{<<"xmlns">>, ?NS_MUCSUB}, {<<"nick">>, Nick}],
children = [#xmlel{name = <<"event">>,
attrs = [{<<"node">>, Node}]}
|| Node <- Nodes]},
IQ = #iq{type = set, id = randoms:get_string(),
xmlns = ?NS_MUCSUB, sub_el = SubEl},
Packet = jlib:iq_to_xml(IQ#iq{sub_el = [SubEl]}),
Config = StateData#state.config,
CaptchaRequired = Config#config.captcha_protected,
PasswordProtected = Config#config.password_protected,
TmpConfig = Config#config{captcha_protected = false,
password_protected = false},
TmpState = StateData#state{config = TmpConfig},
case process_iq_mucsub(From, Packet, IQ, TmpState) of
{result, _, NewState} ->
NewConfig = (NewState#state.config)#config{
captcha_protected = CaptchaRequired,
password_protected = PasswordProtected},
{reply, {ok, get_subscription_nodes(Packet)}, StateName,
NewState#state{config = NewConfig}};
{ignore, NewState} ->
NewConfig = (NewState#state.config)#config{
captcha_protected = CaptchaRequired,
password_protected = PasswordProtected},
{reply, {error, <<"Requrest is ignored">>},
NewState#state{config = NewConfig}};
{error, Err, NewState} ->
NewConfig = (NewState#state.config)#config{
captcha_protected = CaptchaRequired,
password_protected = PasswordProtected},
{reply, {error, get_error_text(Err)}, StateName,
NewState#state{config = NewConfig}};
{error, Err} ->
{reply, {error, get_error_text(Err)}, StateName, StateData}
end;
handle_sync_event({muc_unsubscribe, From}, _From, StateName, StateData) ->
SubEl = #xmlel{name = <<"unsubscribe">>,
attrs = [{<<"xmlns">>, ?NS_MUCSUB}]},
IQ = #iq{type = set, id = randoms:get_string(),
xmlns = ?NS_MUCSUB, sub_el = SubEl},
Packet = jlib:iq_to_xml(IQ),
case process_iq_mucsub(From, Packet, IQ, StateData) of
{result, _, NewState} ->
{reply, ok, StateName, NewState};
{ignore, NewState} ->
{reply, {error, <<"Requrest is ignored">>}, NewState};
{error, Err, NewState} ->
{reply, {error, get_error_text(Err)}, StateName, NewState};
{error, Err} ->
{reply, {error, get_error_text(Err)}, StateName, StateData}
end;
handle_sync_event(_Event, _From, StateName,
StateData) ->
Reply = ok, {reply, Reply, StateName, StateData}.
@ -1346,6 +1400,14 @@ get_error_condition2(Packet) ->
<- EEls],
{condition, Condition}.
get_error_text(Error) ->
case fxml:get_subtag_with_xmlns(Error, <<"text">>, ?NS_STANZAS) of
#xmlel{} = Tag ->
fxml:get_tag_cdata(Tag);
false ->
<<"">>
end.
make_reason(Packet, From, StateData, Reason1) ->
{ok, #user{nick = FromNick}} = (?DICT):find(jid:tolower(From), StateData#state.users),
Condition = get_error_condition(Packet),
@ -4608,6 +4670,18 @@ process_iq_mucsub(From, _Packet,
NewStateData = remove_subscription(From, User, StateData),
store_room(NewStateData),
{result, [], NewStateData};
error when From#jid.lresource == <<"">> ->
{LUser, LServer, _} = LJID,
NewStateData =
dict:fold(
fun({U, S, _}, #user{jid = J, is_subscriber = true} = User,
AccState) when U == LUser, S == LServer ->
remove_subscription(J, User, AccState);
(_, _, AccState) ->
AccState
end, StateData, StateData#state.users),
store_room(NewStateData),
{result, [], NewStateData};
_ ->
{result, [], StateData}
end;