📄 mod_muc_room.erl
字号:
%%%----------------------------------------------------------------------%%% File : mod_muc_room.erl%%% Author : Alexey Shchepin <alexey@sevcom.net>%%% Purpose : MUC room stuff%%% Created : 19 Mar 2003 by Alexey Shchepin <alexey@sevcom.net>%%% Id : $Id: mod_muc_room.erl,v 1.31 2004/10/08 20:40:28 aleksey Exp $%%%-----------------------------------------------------------------------module(mod_muc_room).-author('alexey@sevcom.net').-vsn('$Revision: 1.31 $ ').-behaviour(gen_fsm).%% External exports-export([start/5, start/4, route/4]).%% gen_fsm callbacks-export([init/1, normal_state/2, handle_event/3, handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).-include("ejabberd.hrl").-include("jlib.hrl").-define(SETS, gb_sets).-define(DICT, dict).-record(lqueue, {queue, len, max}).-record(config, {title = "", allow_change_subj = true, allow_query_users = true, allow_private_messages = true, public = true, public_list = true, persistent = false, moderated = false, % TODO members_by_default = true, members_only = false, allow_user_invites = false, password_protected = false, password = "", anonymous = true, logging = false % TODO }).-record(user, {jid, nick, role, last_presence}).-record(state, {room, host, access, jid, config = #config{}, users = ?DICT:new(), affiliations = ?DICT:new(), history = lqueue_new(20), subject = "", subject_author = "", just_created = false}).%-define(DBGFSM, true).-ifdef(DBGFSM).-define(FSMOPTS, [{debug, [trace]}]).-else.-define(FSMOPTS, []).-endif.%%%----------------------------------------------------------------------%%% API%%%----------------------------------------------------------------------start(Host, Access, Room, Creator, Nick) -> gen_fsm:start(?MODULE, [Host, Access, Room, Creator, Nick], ?FSMOPTS).start(Host, Access, Room, Opts) -> gen_fsm:start(?MODULE, [Host, Access, Room, Opts], ?FSMOPTS).%%%----------------------------------------------------------------------%%% Callback functions from gen_fsm%%%----------------------------------------------------------------------%%----------------------------------------------------------------------%% Func: init/1%% Returns: {ok, StateName, StateData} |%% {ok, StateName, StateData, Timeout} |%% ignore |%% {stop, StopReason} %%----------------------------------------------------------------------init([Host, Access, Room, Creator, Nick]) -> State = set_affiliation(Creator, owner, #state{host = Host, access = Access, room = Room, jid = jlib:make_jid(Room, Host, ""), just_created = true}), {ok, normal_state, State};init([Host, Access, Room, Opts]) -> State = set_opts(Opts, #state{host = Host, access = Access, room = Room, jid = jlib:make_jid(Room, Host, "")}), {ok, normal_state, State}.%%----------------------------------------------------------------------%% Func: StateName/2%% Returns: {next_state, NextStateName, NextStateData} |%% {next_state, NextStateName, NextStateData, Timeout} |%% {stop, Reason, NewStateData} %%----------------------------------------------------------------------normal_state({route, From, "", {xmlelement, "message", Attrs, Els} = Packet}, StateData) -> Lang = xml:get_attr_s("xml:lang", Attrs), case is_user_online(From, StateData) of true -> case xml:get_attr_s("type", Attrs) of "groupchat" -> {ok, #user{nick = FromNick, role = Role}} = ?DICT:find(jlib:jid_tolower(From), StateData#state.users), if (Role == moderator) or (Role == participant) -> {NewStateData1, IsAllowed} = case check_subject(Packet) of false -> {StateData, true}; Subject -> case can_change_subject(Role, StateData) of true -> NSD = StateData#state{ subject = Subject, subject_author = FromNick}, case (NSD#state.config)#config.persistent of true -> mod_muc:store_room( NSD#state.room, make_opts(NSD)); _ -> ok end, {NSD, true}; _ -> {StateData, false} end end, case IsAllowed of true -> lists:foreach( fun({_LJID, Info}) -> ejabberd_router:route( jlib:jid_replace_resource( StateData#state.jid, FromNick), Info#user.jid, Packet) end, ?DICT:to_list(StateData#state.users)), NewStateData2 = add_message_to_history(FromNick, Packet, NewStateData1), {next_state, normal_state, NewStateData2}; _ -> ErrText = case (StateData#state.config)#config.allow_change_subj of true -> "Only moderators and participants " "are allowed to change subject in this room"; _ -> "Only moderators " "are allowed to change subject in this room" end, Err = jlib:make_error_reply( Packet, ?ERRT_FORBIDDEN(Lang, ErrText)), ejabberd_router:route( StateData#state.jid, From, Err), {next_state, normal_state, StateData} end; true -> ErrText = "Visitors are not allowed to send messages to all occupants", Err = jlib:make_error_reply( Packet, ?ERRT_FORBIDDEN(Lang, ErrText)), ejabberd_router:route( StateData#state.jid, From, Err), {next_state, normal_state, StateData} end; "error" -> case is_user_online(From, StateData) of true -> NewState = add_user_presence_un( From, {xmlelement, "presence", [{"type", "unavailable"}], []}, StateData), send_new_presence(From, NewState), {next_state, normal_state, remove_online_user(From, NewState)}; _ -> {next_state, normal_state, StateData} end; "chat" -> ErrText = "It is not allowed to send private messages to the conference", Err = jlib:make_error_reply( Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), ejabberd_router:route( StateData#state.jid, From, Err), {next_state, normal_state, StateData}; Type when (Type == "") or (Type == "normal") -> case check_invitation(From, Els, StateData) of error -> ErrText = "It is not allowed to send normal messages to the conference", Err = jlib:make_error_reply( Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), ejabberd_router:route( StateData#state.jid, From, Err), {next_state, normal_state, StateData}; IJID -> Config = StateData#state.config, case Config#config.members_only of true -> case get_affiliation(IJID, StateData) of none -> NSD = set_affiliation( IJID, member, StateData), {next_state, normal_state, NSD}; _ -> {next_state, normal_state, StateData} end; false -> {next_state, normal_state, StateData} end end; _ -> ErrText = "Improper message type", Err = jlib:make_error_reply( Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), ejabberd_router:route( StateData#state.jid, From, Err), {next_state, normal_state, StateData} end; _ -> case xml:get_attr_s("type", Attrs) of "error" -> ok; _ -> ErrText = "Only occupants are allowed to send messages to the conference", Err = jlib:make_error_reply( Packet, ?ERRT_NOT_ACCEPTABLE(Lang, ErrText)), ejabberd_router:route(StateData#state.jid, From, Err) end, {next_state, normal_state, StateData} end;normal_state({route, From, "", {xmlelement, "iq", _Attrs, _Els} = Packet}, StateData) -> case jlib:iq_query_info(Packet) of #iq{type = Type, xmlns = XMLNS, lang = Lang, sub_el = SubEl} = IQ when (XMLNS == ?NS_MUC_ADMIN) or (XMLNS == ?NS_MUC_OWNER) or (XMLNS == ?NS_DISCO_INFO) or (XMLNS == ?NS_DISCO_ITEMS) -> Res1 = case XMLNS of ?NS_MUC_ADMIN -> process_iq_admin(From, Type, Lang, SubEl, StateData); ?NS_MUC_OWNER -> process_iq_owner(From, Type, Lang, SubEl, StateData); ?NS_DISCO_INFO -> process_iq_disco_info(From, Type, Lang, StateData); ?NS_DISCO_ITEMS -> process_iq_disco_items(From, Type, Lang, StateData) end, {IQRes, NewStateData} = case Res1 of {result, Res, SD} -> {IQ#iq{type = result, sub_el = [{xmlelement, "query", [{"xmlns", XMLNS}], Res }]}, SD}; {error, Error} -> {IQ#iq{type = error, sub_el = [SubEl, Error]}, StateData} end, ejabberd_router:route(StateData#state.jid, From, jlib:iq_to_xml(IQRes)), case NewStateData of stop -> {stop, normal, StateData}; _ -> {next_state, normal_state, NewStateData} end; reply -> {next_state, normal_state, StateData}; _ -> Err = jlib:make_error_reply( Packet, ?ERR_FEATURE_NOT_IMPLEMENTED), ejabberd_router:route(StateData#state.jid, From, Err), {next_state, normal_state, StateData} end;normal_state({route, From, Nick, {xmlelement, "presence", Attrs, _Els} = Packet}, StateData) -> Type = xml:get_attr_s("type", Attrs), Lang = xml:get_attr_s("xml:lang", Attrs), StateData1 = case Type of "unavailable" -> case is_user_online(From, StateData) of true -> NewState = add_user_presence_un(From, Packet, StateData), send_new_presence(From, NewState), remove_online_user(From, NewState); _ -> StateData end; "error" -> case is_user_online(From, StateData) of true -> NewState = add_user_presence_un( From, {xmlelement, "presence", [{"type", "unavailable"}], []}, StateData), send_new_presence(From, NewState), remove_online_user(From, NewState); _ -> StateData end; "" -> case is_user_online(From, StateData) of true -> case is_nick_change(From, Nick, StateData) of true -> case {is_nick_exists(Nick, StateData), mod_muc:can_use_nick(From, Nick)} of {true, _} -> Lang = xml:get_attr_s("xml:lang", Attrs), ErrText = "Nickname is already in use by another occupant", Err = jlib:make_error_reply( Packet, ?ERRT_CONFLICT(Lang, ErrText)), ejabberd_router:route( jlib:jid_replace_resource( StateData#state.jid, Nick), % TODO: s/Nick/""/ From, Err), StateData; {_, false} -> ErrText = "Nickname is registered by another person", Err = jlib:make_error_reply( Packet, ?ERRT_CONFLICT(Lang, ErrText)), ejabberd_router:route( % TODO: s/Nick/""/ jlib:jid_replace_resource( StateData#state.jid, Nick), From, Err), StateData; _ -> change_nick(From, Nick, StateData) end; _ -> NewState = add_user_presence(From, Packet, StateData), send_new_presence(From, NewState), NewState end; _ -> add_new_user(From, Nick, Packet, StateData) end; _ -> StateData end, %io:format("STATE1: ~p~n", [?DICT:to_list(StateData#state.users)]), %io:format("STATE2: ~p~n", [?DICT:to_list(StateData1#state.users)]), case (not (StateData1#state.config)#config.persistent) andalso (?DICT:to_list(StateData1#state.users) == []) of true -> {stop, normal, StateData1}; _ -> {next_state, normal_state, StateData1} end;normal_state({route, From, ToNick, {xmlelement, "message", Attrs, _Els} = Packet}, StateData) -> Type = xml:get_attr_s("type", Attrs), Lang = xml:get_attr_s("xml:lang", Attrs), case Type of "error" -> case is_user_online(From, StateData) of true -> NewState = add_user_presence_un( From, {xmlelement, "presence", [{"type", "unavailable"}], []}, StateData), send_new_presence(From, NewState), {next_state, normal_state, remove_online_user(From, NewState)}; _ -> {next_state, normal_state, StateData} end; _ -> case (StateData#state.config)#config.allow_private_messages andalso is_user_online(From, StateData) of true -> case Type of "groupchat" -> ErrText = "It is not allowed to send private " "messages of type \"groupchat\"", Err = jlib:make_error_reply( Packet, ?ERRT_BAD_REQUEST(Lang, ErrText)), ejabberd_router:route( jlib:jid_replace_resource( StateData#state.jid, ToNick), From, Err); _ -> case find_jid_by_nick(ToNick, StateData) of false -> ErrText = "Recipient is not in the conference room", Err = jlib:make_error_reply( Packet, ?ERRT_ITEM_NOT_FOUND(Lang, ErrText)),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -