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").
{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,
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,
[
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}.
<- 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),
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;