diff options
author | Evgeniy Khramtsov <ekhramtsov@process-one.net> | 2018-04-14 18:32:12 +0300 |
---|---|---|
committer | Evgeniy Khramtsov <ekhramtsov@process-one.net> | 2018-04-14 18:32:12 +0300 |
commit | a5284229cbbb2237f31645f39066680a97ffe6b0 (patch) | |
tree | f9773e0390fa800c488ba0b2f1f2e7d21efe90d2 /src | |
parent | Clear fast_tls cache on configuration reload (diff) | |
parent | Merge branch 'master' into muc-self-presence (diff) |
Merge branch 'muc-self-presence'
Diffstat (limited to 'src')
-rw-r--r-- | src/mod_caps.erl | 21 | ||||
-rw-r--r-- | src/mod_muc_room.erl | 119 | ||||
-rw-r--r-- | src/mod_vcard_xupdate.erl | 2 |
3 files changed, 115 insertions, 27 deletions
diff --git a/src/mod_caps.erl b/src/mod_caps.erl index 995e8b487..19838cc8a 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -38,7 +38,8 @@ -export([read_caps/1, list_features/1, caps_stream_features/2, disco_features/5, disco_identity/5, disco_info/5, get_features/2, export/1, import_info/0, import/5, - get_user_caps/2, import_start/2, import_stop/2]). + get_user_caps/2, import_start/2, import_stop/2, + compute_disco_hash/2, is_valid_node/1]). %% gen_mod callbacks -export([start/2, stop/1, reload/3, depends/2]). @@ -412,13 +413,13 @@ make_my_disco_hash(Host) -> DiscoInfo = #disco_info{identities = Identities, features = Feats, xdata = Info}, - make_disco_hash(DiscoInfo, sha); + compute_disco_hash(DiscoInfo, sha); _Err -> <<"">> end. -type digest_type() :: md5 | sha | sha224 | sha256 | sha384 | sha512. --spec make_disco_hash(disco_info(), digest_type()) -> binary(). -make_disco_hash(DiscoInfo, Algo) -> +-spec compute_disco_hash(disco_info(), digest_type()) -> binary(). +compute_disco_hash(DiscoInfo, Algo) -> Concat = list_to_binary([concat_identities(DiscoInfo), concat_features(DiscoInfo), concat_info(DiscoInfo)]), base64:encode(case Algo of @@ -434,17 +435,17 @@ make_disco_hash(DiscoInfo, Algo) -> check_hash(Caps, DiscoInfo) -> case Caps#caps.hash of <<"md5">> -> - Caps#caps.version == make_disco_hash(DiscoInfo, md5); + Caps#caps.version == compute_disco_hash(DiscoInfo, md5); <<"sha-1">> -> - Caps#caps.version == make_disco_hash(DiscoInfo, sha); + Caps#caps.version == compute_disco_hash(DiscoInfo, sha); <<"sha-224">> -> - Caps#caps.version == make_disco_hash(DiscoInfo, sha224); + Caps#caps.version == compute_disco_hash(DiscoInfo, sha224); <<"sha-256">> -> - Caps#caps.version == make_disco_hash(DiscoInfo, sha256); + Caps#caps.version == compute_disco_hash(DiscoInfo, sha256); <<"sha-384">> -> - Caps#caps.version == make_disco_hash(DiscoInfo, sha384); + Caps#caps.version == compute_disco_hash(DiscoInfo, sha384); <<"sha-512">> -> - Caps#caps.version == make_disco_hash(DiscoInfo, sha512); + Caps#caps.version == compute_disco_hash(DiscoInfo, sha512); _ -> true end. diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 87ae28797..158e937c7 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -290,7 +290,7 @@ normal_state({route, <<"">>, process_iq_admin(From, IQ, StateData); ?NS_MUC_OWNER -> process_iq_owner(From, IQ, StateData); - ?NS_DISCO_INFO when SubEl#disco_info.node == <<>> -> + ?NS_DISCO_INFO -> process_iq_disco_info(From, IQ, StateData); ?NS_DISCO_ITEMS -> process_iq_disco_items(From, IQ, StateData); @@ -2068,12 +2068,30 @@ presence_broadcast_allowed(JID, StateData) -> -spec send_initial_presences_and_messages( jid(), binary(), presence(), state(), state()) -> ok. send_initial_presences_and_messages(From, Nick, Presence, NewState, OldState) -> + send_self_presence(From, NewState), send_existing_presences(From, NewState), send_initial_presence(From, NewState, OldState), History = get_history(Nick, Presence, NewState), send_history(From, History, NewState), send_subject(From, OldState). +-spec send_self_presence(jid(), state()) -> ok. +send_self_presence(JID, State) -> + AvatarHash = (State#state.config)#config.vcard_xupdate, + DiscoInfo = make_disco_info(JID, State), + DiscoHash = mod_caps:compute_disco_hash(DiscoInfo, sha), + Els1 = [#caps{hash = <<"sha-1">>, + node = ?EJABBERD_URI, + version = DiscoHash}], + Els2 = if is_binary(AvatarHash) -> + [#vcard_xupdate{hash = AvatarHash}|Els1]; + true -> + Els1 + end, + ejabberd_router:route(#presence{from = State#state.jid, to = JID, + id = randoms:get_string(), + sub_els = Els2}). + -spec send_initial_presence(jid(), state(), state()) -> ok. send_initial_presence(NJID, StateData, OldStateData) -> send_new_presence1(NJID, <<"">>, true, StateData, OldStateData). @@ -3344,12 +3362,15 @@ send_config_change_info(New, #state{config = Old} = StateData) -> end ++ case Old#config{anonymous = New#config.anonymous, - vcard = New#config.vcard, logging = New#config.logging} of New -> []; _ -> [104] end, if Codes /= [] -> + lists:foreach( + fun({_LJID, #user{jid = JID}}) -> + send_self_presence(JID, StateData#state{config = New}) + end, ?DICT:to_list(StateData#state.users)), Message = #message{type = groupchat, id = randoms:get_string(), sub_els = [#muc_user{status_codes = Codes}]}, @@ -3377,7 +3398,8 @@ remove_nonmembers(StateData) -> StateData, (?DICT):to_list(get_users_and_subscribers(StateData))). -spec set_opts([{atom(), any()}], state()) -> state(). -set_opts([], StateData) -> StateData; +set_opts([], StateData) -> + set_vcard_xupdate(StateData); set_opts([{Opt, Val} | Opts], StateData) -> NSD = case Opt of title -> @@ -3492,6 +3514,10 @@ set_opts([{Opt, Val} | Opts], StateData) -> StateData#state{config = (StateData#state.config)#config{vcard = Val}}; + vcard_xupdate -> + StateData#state{config = + (StateData#state.config)#config{vcard_xupdate = + Val}}; pubsub -> StateData#state{config = (StateData#state.config)#config{pubsub = Val}}; @@ -3526,6 +3552,20 @@ set_opts([{Opt, Val} | Opts], StateData) -> end, set_opts(Opts, NSD). +set_vcard_xupdate(#state{config = + #config{vcard = VCardRaw, + vcard_xupdate = undefined} = Config} = State) + when VCardRaw /= <<"">> -> + case fxml_stream:parse_element(VCardRaw) of + {error, _} -> + State; + El -> + Hash = mod_vcard_xupdate:compute_hash(El), + State#state{config = Config#config{vcard_xupdate = Hash}} + end; +set_vcard_xupdate(State) -> + State. + -define(MAKE_CONFIG_OPT(Opt), {get_config_opt_name(Opt), element(Opt, Config)}). @@ -3561,6 +3601,7 @@ make_opts(StateData) -> ?MAKE_CONFIG_OPT(#config.presence_broadcast), ?MAKE_CONFIG_OPT(#config.voice_request_min_interval), ?MAKE_CONFIG_OPT(#config.vcard), + ?MAKE_CONFIG_OPT(#config.vcard_xupdate), ?MAKE_CONFIG_OPT(#config.pubsub), {captcha_whitelist, (?SETS):to_list((StateData#state.config)#config.captcha_whitelist)}, @@ -3633,12 +3674,8 @@ destroy_room(DEl, StateData) -> false -> Fiffalse end). --spec process_iq_disco_info(jid(), iq(), state()) -> - {result, disco_info()} | {error, stanza_error()}. -process_iq_disco_info(_From, #iq{type = set, lang = Lang}, _StateData) -> - Txt = <<"Value 'set' of 'type' attribute is not allowed">>, - {error, xmpp:err_not_allowed(Txt, Lang)}; -process_iq_disco_info(_From, #iq{type = get, lang = Lang}, StateData) -> +-spec make_disco_info(jid(), state()) -> disco_info(). +make_disco_info(_From, StateData) -> Config = StateData#state.config, Feats = [?NS_VCARD, ?NS_MUC, ?CONFIG_OPT_TO_FEATURE((Config#config.public), @@ -3664,11 +3701,35 @@ process_iq_disco_info(_From, #iq{type = get, lang = Lang}, StateData) -> _ -> [] end, - {result, #disco_info{xdata = [iq_disco_info_extras(Lang, StateData)], - identities = [#identity{category = <<"conference">>, - type = <<"text">>, - name = get_title(StateData)}], - features = Feats}}. + #disco_info{identities = [#identity{category = <<"conference">>, + type = <<"text">>, + name = get_title(StateData)}], + features = Feats}. + +-spec process_iq_disco_info(jid(), iq(), state()) -> + {result, disco_info()} | {error, stanza_error()}. +process_iq_disco_info(_From, #iq{type = set, lang = Lang}, _StateData) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + {error, xmpp:err_not_allowed(Txt, Lang)}; +process_iq_disco_info(From, #iq{type = get, lang = Lang, + sub_els = [#disco_info{node = <<>>}]}, + StateData) -> + DiscoInfo = make_disco_info(From, StateData), + Extras = iq_disco_info_extras(Lang, StateData), + {result, DiscoInfo#disco_info{xdata = [Extras]}}; +process_iq_disco_info(From, #iq{type = get, lang = Lang, + sub_els = [#disco_info{node = Node}]}, + StateData) -> + try + true = mod_caps:is_valid_node(Node), + DiscoInfo = make_disco_info(From, StateData), + Hash = mod_caps:compute_disco_hash(DiscoInfo, sha), + Node = <<(?EJABBERD_URI)/binary, $#, Hash/binary>>, + {result, DiscoInfo#disco_info{node = Node}} + catch _:{badmatch, _} -> + Txt = <<"Invalid node name">>, + {error, xmpp:err_item_not_found(Txt, Lang)} + end. -spec iq_disco_info_extras(binary(), state()) -> xdata(). iq_disco_info_extras(Lang, StateData) -> @@ -3734,13 +3795,15 @@ process_iq_vcard(_From, #iq{type = get}, StateData) -> {error, _} -> {error, xmpp:err_item_not_found()} end; -process_iq_vcard(From, #iq{type = set, lang = Lang, sub_els = [SubEl]}, +process_iq_vcard(From, #iq{type = set, lang = Lang, sub_els = [Pkt]}, StateData) -> case get_affiliation(From, StateData) of owner -> - VCardRaw = fxml:element_to_binary(xmpp:encode(SubEl)), + SubEl = xmpp:encode(Pkt), + VCardRaw = fxml:element_to_binary(SubEl), + Hash = mod_vcard_xupdate:compute_hash(SubEl), Config = StateData#state.config, - NewConfig = Config#config{vcard = VCardRaw}, + NewConfig = Config#config{vcard = VCardRaw, vcard_xupdate = Hash}, change_config(NewConfig, StateData); _ -> ErrText = <<"Owner privileges required">>, @@ -4162,6 +4225,28 @@ send_wrapped(From, To, Packet, Node, State) -> ok end; true -> + case Packet of + #presence{type = unavailable} -> + case xmpp:get_subtag(Packet, #muc_user{}) of + #muc_user{destroy = Destroy, + status_codes = Codes} -> + case Destroy /= undefined orelse + (lists:member(110,Codes) andalso + not lists:member(303, Codes)) of + true -> + ejabberd_router:route( + #presence{from = State#state.jid, to = To, + id = randoms:get_string(), + type = unavailable}); + false -> + ok + end; + _ -> + false + end; + _ -> + ok + end, ejabberd_router:route(xmpp:set_from_to(Packet, From, To)) end. diff --git a/src/mod_vcard_xupdate.erl b/src/mod_vcard_xupdate.erl index 867e5ae25..5c10a5a7e 100644 --- a/src/mod_vcard_xupdate.erl +++ b/src/mod_vcard_xupdate.erl @@ -33,6 +33,8 @@ -export([update_presence/1, vcard_set/1, remove_user/2, user_send_packet/1, mod_opt_type/1, mod_options/1, depends/2]). +%% API +-export([compute_hash/1]). -include("ejabberd.hrl"). -include("logger.hrl"). |