diff --git a/big_tests/rebar.config b/big_tests/rebar.config index 9b7332a7fb2..a0c145eabb1 100644 --- a/big_tests/rebar.config +++ b/big_tests/rebar.config @@ -8,13 +8,13 @@ %% We use https:// instead of git:// {deps, [ - {exml, "3.4.1", {pkg, hexml}}, + {exml, "4.0.0", {pkg, hexml}}, {bbmustache, "1.12.2"}, {jiffy, "1.1.2"}, {proper, "1.4.0"}, {gun, "2.1.0"}, {fusco, "0.1.1"}, - {escalus, "4.2.16"}, + {escalus, "4.3.0"}, {cowboy, "2.12.0"}, {csv, "3.0.3", {pkg, csve}}, {amqp_client, "4.0.3"}, diff --git a/big_tests/rebar.lock b/big_tests/rebar.lock index 9cb3749ea15..e1ceedce3cc 100644 --- a/big_tests/rebar.lock +++ b/big_tests/rebar.lock @@ -1,6 +1,5 @@ {"1.2.0", [{<<"amqp_client">>,{pkg,<<"amqp_client">>,<<"4.0.3">>},0}, - {<<"base16">>,{pkg,<<"base16">>,<<"2.0.1">>},1}, {<<"bbmustache">>,{pkg,<<"bbmustache">>,<<"1.12.2">>},0}, {<<"cowboy">>,{pkg,<<"cowboy">>,<<"2.12.0">>},0}, {<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.13.0">>},1}, @@ -11,17 +10,17 @@ {<<"ct_groups_summary_hook">>, {pkg,<<"ct_groups_summary_hook">>,<<"0.1.1">>}, 0}, - {<<"escalus">>,{pkg,<<"escalus">>,<<"4.2.16">>},0}, + {<<"escalus">>,{pkg,<<"escalus">>,<<"4.3.0">>},0}, {<<"esip">>,{pkg,<<"esip">>,<<"1.0.56">>},0}, - {<<"exml">>,{pkg,<<"hexml">>,<<"3.4.1">>},0}, - {<<"fast_pbkdf2">>,{pkg,<<"fast_pbkdf2">>,<<"1.0.5">>},2}, - {<<"fast_scram">>,{pkg,<<"fast_scram">>,<<"0.6.0">>},1}, + {<<"exml">>,{pkg,<<"hexml">>,<<"4.0.0">>},0}, + {<<"fast_pbkdf2">>,{pkg,<<"fast_pbkdf2">>,<<"1.0.6">>},2}, + {<<"fast_scram">>,{pkg,<<"fast_scram">>,<<"0.6.1">>},1}, {<<"fast_tls">>,{pkg,<<"fast_tls">>,<<"1.1.21">>},1}, {<<"fusco">>,{pkg,<<"fusco">>,<<"0.1.1">>},0}, {<<"gun">>,{pkg,<<"gun">>,<<"2.1.0">>},0}, {<<"jid">>,{pkg,<<"mongoose_jid">>,<<"2.2.0">>},0}, {<<"jiffy">>,{pkg,<<"jiffy">>,<<"1.1.2">>},0}, - {<<"meck">>,{pkg,<<"meck">>,<<"0.9.2">>},1}, + {<<"meck">>,{pkg,<<"meck">>,<<"1.0.0">>},1}, {<<"p1_utils">>,{pkg,<<"p1_utils">>,<<"1.0.26">>},1}, {<<"proper">>,{pkg,<<"proper">>,<<"1.4.0">>},0}, {<<"quickrand">>,{pkg,<<"quickrand">>,<<"2.0.7">>},2}, @@ -33,28 +32,27 @@ {<<"thoas">>,{pkg,<<"thoas">>,<<"1.2.1">>},1}, {<<"uuid">>,{pkg,<<"uuid_erl">>,<<"2.0.7">>},1}, {<<"wait_helper">>,{pkg,<<"wait_helper">>,<<"0.2.1">>},0}, - {<<"worker_pool">>,{pkg,<<"worker_pool">>,<<"6.2.1">>},1}]}. + {<<"worker_pool">>,{pkg,<<"worker_pool">>,<<"6.4.0">>},1}]}. [ {pkg_hash,[ {<<"amqp_client">>, <<"C7DCC8031C780CD39EC586BA827A8EB26E006E9761AF8D3F58FDED11F645EBD4">>}, - {<<"base16">>, <<"F0549F732E03BE8124ED0D19FD5EE52146CC8BE24C48CBC3F23AB44B157F11A2">>}, {<<"bbmustache">>, <<"0CABDCE0DB9FE6D3318131174B9F2B351328A4C0AFBEB3E6E99BB0E02E9B621D">>}, {<<"cowboy">>, <<"F276D521A1FF88B2B9B4C54D0E753DA6C66DD7BE6C9FCA3D9418B561828A3731">>}, {<<"cowlib">>, <<"DB8F7505D8332D98EF50A3EF34B34C1AFDDEC7506E4EE4DD4A3A266285D282CA">>}, {<<"credentials_obfuscation">>, <<"34E18B126B3AEFD6E8143776FBE1CECEEA6792307C99AC5EE8687911F048CFD7">>}, {<<"csv">>, <<"69E7D9B3FDC72016644368762C6A3E6CBFEB85BCCADBF1BD99AB6C827E360E04">>}, {<<"ct_groups_summary_hook">>, <<"21B94902B6CF2D345F4D790D34B49654E71CB8E570DCCC9C1C3616DAE720A7AA">>}, - {<<"escalus">>, <<"EC83C277DECD721C3B219823C159D66CF94981A0796473617E4C0835E7395FE5">>}, + {<<"escalus">>, <<"80301D57F4C863FA95F09AE148524508F18D7389B5070E2A5FFB7A38B51527C5">>}, {<<"esip">>, <<"63C0FDC667BE751714E1E5C14621A9334F21B60AC1BB68BE889454CA9CA021B7">>}, - {<<"exml">>, <<"9581FE6512D9772C61BBE611CD4A8E5BB90B4D4481275325EC520F7A931A9393">>}, - {<<"fast_pbkdf2">>, <<"6045138C4C209FC8222A0B18B2CB1D7BD7407EF4ADAD0F14C5E0F7F4726E3E41">>}, - {<<"fast_scram">>, <<"70724F584A118DA147A51EE38DEE56203F217D58AD61E0BB2C2EF834C16B35B8">>}, + {<<"exml">>, <<"54C1AAD5BD290EC31C19CE4A5D449C7E3236107AA2D3610FC04FC963DC8EAF13">>}, + {<<"fast_pbkdf2">>, <<"199BCEC73A1A246941E9465D3DC41052953B638128841ED24B29ED03CF70AF27">>}, + {<<"fast_scram">>, <<"BEEADB03D774640F0671681759CE53B2FF33CB58C86FD9BF2A793E2FC1ED0F5D">>}, {<<"fast_tls">>, <<"65D7D547A09EEFB37A1C0D04D8601FAC4F3E6E2C1EDE859A7787081670F9648D">>}, {<<"fusco">>, <<"3DD6A90151DFEF30EA1937CC44E9A59177C0094918388D9BCAA2F2DC5E2AE4AA">>}, {<<"gun">>, <<"B4E4CBBF3026D21981C447E9E7CA856766046EFF693720BA43114D7F5DE36E87">>}, {<<"jid">>, <<"3761535829A0DBA5A6BBDF2EE6EA7BCD9A8F1ADA201EDB4D79E1E2B47D5FD3D6">>}, {<<"jiffy">>, <<"A9B6C9A7EC268E7CF493D028F0A4C9144F59CCB878B1AFE42841597800840A1B">>}, - {<<"meck">>, <<"85CCBAB053F1DB86C7CA240E9FC718170EE5BDA03810A6292B5306BF31BAE5F5">>}, + {<<"meck">>, <<"24676CB6EE6951530093A93EDCD410CFE4CB59FE89444B875D35C9D3909A15D0">>}, {<<"p1_utils">>, <<"67B0C4AC9FA3BA3EF563B31AA111B0A004439A37FAC85E027F1C3617E1C7EC6C">>}, {<<"proper">>, <<"89A44B8C39D28BB9B4BE8E4D715D534905B325470F2E0EC5E004D12484A79434">>}, {<<"quickrand">>, <<"D2BD76676A446E6A058D678444B7FDA1387B813710D1AF6D6E29BB92186C8820">>}, @@ -66,27 +64,26 @@ {<<"thoas">>, <<"19A25F31177A17E74004D4840F66D791D4298C5738790FA2CC73731EB911F195">>}, {<<"uuid">>, <<"B2078D2CC814F53AFA52D36C91E08962C7E7373585C623F4C0EA6DFB04B2AF94">>}, {<<"wait_helper">>, <<"942967D8B84A2F62DC13F57C7F1B3182D0DA8D3F8D2B4210E85427E12164D8FF">>}, - {<<"worker_pool">>, <<"BD98A0BE1D20057AE9967CBE73D263AEA5BE14BBE4C73CAFEB1378572FF14561">>}]}, + {<<"worker_pool">>, <<"0347B805A8E5804B5676A9885FB3B9B6C1627099C449C3C67C0E8E6AF79E9AA6">>}]}, {pkg_hash_ext,[ {<<"amqp_client">>, <<"AE945F7280617E9A4B17A6D49E3A2F496D716E8088EC29D8E94ECC79E5DA7458">>}, - {<<"base16">>, <<"06EA2D48343282E712160BA89F692B471DB8B36ABE8394F3445FF9032251D772">>}, {<<"bbmustache">>, <<"688B33A4D5CC2D51F575ADF0B3683FC40A38314A2F150906EDCFC77F5B577B3B">>}, {<<"cowboy">>, <<"8A7ABE6D183372CEB21CAA2709BEC928AB2B72E18A3911AA1771639BEF82651E">>}, {<<"cowlib">>, <<"E1E1284DC3FC030A64B1AD0D8382AE7E99DA46C3246B815318A4B848873800A4">>}, {<<"credentials_obfuscation">>, <<"738ACE0ED5545D2710D3F7383906FC6F6B582D019036E5269C4DBD85DBCED566">>}, {<<"csv">>, <<"741D1A55AABADAA3E0FE13051050101A73E90C4570B9F9403A939D9546813521">>}, {<<"ct_groups_summary_hook">>, <<"997CDE48FEB0C398989E4091A341D4FFF43CFA06CDB8FB2E80CC4A0E0362691C">>}, - {<<"escalus">>, <<"3CA9D58F39A3FBD618A1E7B5D57AE97B76016330BB2374C430AA9278669243CC">>}, + {<<"escalus">>, <<"8C4D39677D55C48B04EDE4EAC0FD0AD2A574BEDE7180761E6E3D3877900C7708">>}, {<<"esip">>, <<"9EF3660CEF93B623F7368DCD5C79F4E704358631909E6DD464E335378815DA1F">>}, - {<<"exml">>, <<"D8E7894E2544402B4986EEB2443C15B51B14F686266F091DBF2777D1D99A2FA2">>}, - {<<"fast_pbkdf2">>, <<"BC3B5A3CAB47AD114FF8BB815FEDE62A6187ACD14D8B37412F2AF8236A089CEF">>}, - {<<"fast_scram">>, <<"771D034341599CFC6A6C5E56CF924B68D2C7478088CAF17419E3147B66914667">>}, + {<<"exml">>, <<"08CC97527C708D57A03F467049AC260B5951BD67906AA154BE56B5D8BDD3238C">>}, + {<<"fast_pbkdf2">>, <<"35EEC22629AAA739915843C7B7DE0D84657D1ECE972D8BBC86368747E9C14012">>}, + {<<"fast_scram">>, <<"FE0650A309FDF97C75E1EA812CCFB40EB464ECAFD3783E83AA17C7F572EDAB0B">>}, {<<"fast_tls">>, <<"131542913937025E48CD80AA81F00359686D5501B75621E72026A87B5229505B">>}, {<<"fusco">>, <<"6343551BD1E824F2A6CA85E1158C5B37C320FD449FBFEC7450A73F192AAF9022">>}, {<<"gun">>, <<"52FC7FC246BFC3B00E01AEA1C2854C70A366348574AB50C57DFE796D24A0101D">>}, {<<"jid">>, <<"0F2C69E4C142E21E7D87E6D70AC62ECF6EB00E97C86CF8CBF6BAD4B3BE8B0545">>}, {<<"jiffy">>, <<"BB61BC42A720BBD33CB09A410E48BB79A61012C74CB8B3E75F26D988485CF381">>}, - {<<"meck">>, <<"81344F561357DC40A8344AFA53767C32669153355B626EA9FCBC8DA6B3045826">>}, + {<<"meck">>, <<"680A9BCFE52764350BEB9FB0335FB75FEE8E7329821416CEE0A19FEC35433882">>}, {<<"p1_utils">>, <<"D0379E8C1156B98BD64F8129C1DE022FCCA4F2FDB7486CE73BF0ED2C3376B04C">>}, {<<"proper">>, <<"18285842185BD33EFBDA97D134A5CB5A0884384DB36119FEE0E3CFA488568CBB">>}, {<<"quickrand">>, <<"B8ACBF89A224BC217C3070CA8BEBC6EB236DBE7F9767993B274084EA044D35F0">>}, @@ -98,5 +95,5 @@ {<<"thoas">>, <<"E38697EDFFD6E91BD12CEA41B155115282630075C2A727E7A6B2947F5408B86A">>}, {<<"uuid">>, <<"4E4C5CA3461DC47C5E157ED42AA3981A053B7A186792AF972A27B14A9489324E">>}, {<<"wait_helper">>, <<"88FCA7983E1E8A0650FD98062C273E67E807F072C0046C2B102A53FDF467DEEC">>}, - {<<"worker_pool">>, <<"64E560DE08CA5E7DB8BD4CDCC7B744B0659696194E3BC9E56239BA4A0F7E24F9">>}]} + {<<"worker_pool">>, <<"59946FBCE1D331CDEB153EDD36A823DC1AAB4C2482662582B983C9C90EBC3461">>}]} ]. diff --git a/big_tests/src/ct_mongoose_log_hook.erl b/big_tests/src/ct_mongoose_log_hook.erl index bc80f3a6e14..c3e406c0901 100644 --- a/big_tests/src/ct_mongoose_log_hook.erl +++ b/big_tests/src/ct_mongoose_log_hook.erl @@ -155,7 +155,7 @@ write_lines([], _CurrentLineNum, _Writer) -> make_elem(CurrentLineNum, Line) when is_integer(CurrentLineNum), is_binary(Line) -> NextLinkName = make_link_name(CurrentLineNum+1), [#xmlcdata{ content = make_content(CurrentLineNum, Line) }, - #xmlel{name = <<"a">>, attrs = [{<<"name">>, NextLinkName}]}]. + #xmlel{name = <<"a">>, attrs = #{<<"name">> => NextLinkName}}]. make_link_name(Line) when is_integer(Line) -> <<"L", (list_to_binary(integer_to_list(Line)))/binary>>. diff --git a/big_tests/src/dynamic_compile.erl b/big_tests/src/dynamic_compile.erl deleted file mode 100644 index 25b73590d90..00000000000 --- a/big_tests/src/dynamic_compile.erl +++ /dev/null @@ -1,309 +0,0 @@ -%% Copyright (c) 2007 -%% Mats Cronqvist -%% Chris Newcombe -%% Jacob Vorreuter -%% -%% Permission is hereby granted, free of charge, to any person -%% obtaining a copy of this software and associated documentation -%% files (the "Software"), to deal in the Software without -%% restriction, including without limitation the rights to use, -%% copy, modify, merge, publish, distribute, sublicense, and/or sell -%% copies of the Software, and to permit persons to whom the -%% Software is furnished to do so, subject to the following -%% conditions: -%% -%% The above copyright notice and this permission notice shall be -%% included in all copies or substantial portions of the Software. -%% -%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -%% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -%% OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -%% NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -%% HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -%% WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -%% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -%% OTHER DEALINGS IN THE SOFTWARE. - -%%%------------------------------------------------------------------- -%%% File : dynamic_compile.erl -%%% Description : -%%% Authors : Mats Cronqvist -%%% Chris Newcombe -%%% Jacob Vorreuter -%%% TODO : -%%% - add support for limit include-file depth (and prevent circular references) -%%% prevent circular macro expansion set FILE correctly when -module() is found -%%% -include_lib support $ENVVAR in include filenames -%%% substitute-stringize (??MACRO) -%%% -undef/-ifdef/-ifndef/-else/-endif -%%% -file(File, Line) -%%%------------------------------------------------------------------- - -%% This module is still used in tests --module(dynamic_compile). - -%% API --export([from_string/1, from_string/2]). - --ignore_xref([from_string/1]). --ignore_xref([from_string/2]). - --import(lists, [reverse/1, keyreplace/4]). - --type macro_dict() :: dict:dict(term(), term()). - -%%==================================================================== -%% API -%%==================================================================== - -%% @doc Returns a binary that can be used with -%% code:load_binary(Module, ModuleFilenameForInternalRecords, Binary). --spec from_string('eof' | string()) -> {_, binary()}. -from_string(CodeStr) -> - from_string(CodeStr, []). - -%% @doc takes Options as for compile:forms/2 --spec from_string('eof' | string(), [any()]) -> {_, binary()}. -from_string(CodeStr, CompileFormsOptions) -> - %% Initialise the macro dictionary with the default predefined macros, - %% (adapted from epp.erl:predef_macros/1 - Filename = "compiled_from_string", - %%Machine = list_to_atom(erlang:system_info(machine)), - Ms0 = dict:new(), - % Ms1 = dict:store('FILE', {[], "compiled_from_string"}, Ms0), - % Ms2 = dict:store('LINE', {[], 1}, Ms1), % actually we might add special code for this - % Ms3 = dict:store('MODULE', {[], undefined}, Ms2), - % Ms4 = dict:store('MODULE_STRING', {[], undefined}, Ms3), - % Ms5 = dict:store('MACHINE', {[], Machine}, Ms4), - % InitMD = dict:store(Machine, {[], true}, Ms5), - InitMD = Ms0, - - %% From the docs for compile:forms: - %% When encountering an -include or -include_dir directive, the compiler searches for header files in the following directories: - %% 1. ".", the current working directory of the file server; - %% 2. the base name of the compiled file; - %% 3. the directories specified using the i option. The directory specified last is searched first. - %% In this case, #2 is meaningless. - IncludeSearchPath = ["." | reverse([Dir || {i, Dir} <- CompileFormsOptions])], - {RevForms, _OutMacroDict} = scan_and_parse(CodeStr, Filename, 1, [], InitMD, IncludeSearchPath), - Forms = reverse(RevForms), - - %% note: 'binary' is forced as an implicit option, whether it is provided or not. - case compile:forms(Forms, CompileFormsOptions) of - {ok, ModuleName, CompiledCodeBinary} when is_binary(CompiledCodeBinary) -> - {ModuleName, CompiledCodeBinary}; - {ok, ModuleName, CompiledCodeBinary, []} when is_binary(CompiledCodeBinary) -> % empty warnings list - {ModuleName, CompiledCodeBinary}; - {ok, _ModuleName, _CompiledCodeBinary, Warnings} -> - throw({?MODULE, warnings, Warnings}); - Other -> - throw({?MODULE, compile_forms, Other}) - end. - -%%==================================================================== -%% Internal functions -%%==================================================================== - -%% @doc Code from Mats Cronqvist
-%% See http://www.erlang.org/pipermail/erlang-questions/2007-March/025507.html -%% 'scan_and_parse' -%% basically we call the OTP scanner and parser (erl_scan and -%% erl_parse) line-by-line, but check each scanned line for (or -%% definitions of) macros before parsing. returns {ReverseForms, FinalMacroDict} -%% @private --spec scan_and_parse('eof' | string(), - _CurrFilename :: file:name(), - _CurrLine :: integer() | {integer(), pos_integer()}, - RevForms :: [any()], - MacroDict :: macro_dict(), - _IncludeSearchPath :: [file:name()]) -> {[any()], macro_dict()}. -scan_and_parse([], _CurrFilename, _CurrLine, RevForms, MacroDict, _IncludeSearchPath) -> - {RevForms, MacroDict}; -scan_and_parse(RemainingText, CurrFilename, CurrLine, RevForms, MacroDict, IncludeSearchPath) -> - case scanner(RemainingText, CurrLine, MacroDict) of - {tokens, NLine, NRemainingText, Toks} -> - {ok, Form} = erl_parse:parse_form(Toks), - scan_and_parse(NRemainingText, CurrFilename, NLine, [Form | RevForms], MacroDict, IncludeSearchPath); - {macro, NLine, NRemainingText, NMacroDict} -> - scan_and_parse(NRemainingText, CurrFilename, NLine, RevForms, NMacroDict, IncludeSearchPath); - {include, NLine, NRemainingText, IncludeFilename} -> - IncludeFileRemainingTextents = read_include_file(IncludeFilename, IncludeSearchPath), - %%io:format("include file ~p contents: ~n~p~nRemainingText = ~p~n", [IncludeFilename, IncludeFileRemainingTextents, RemainingText]), - %% Modify the FILE macro to reflect the filename - %%IncludeMacroDict = dict:store('FILE', {[], IncludeFilename}, MacroDict), - IncludeMacroDict = MacroDict, - - %% Process the header file (inc. any nested header files) - {RevIncludeForms, IncludedMacroDict} = scan_and_parse(IncludeFileRemainingTextents, IncludeFilename, 1, [], IncludeMacroDict, IncludeSearchPath), - %io:format("include file results = ~p~n", [R]), - %% Restore the FILE macro in the NEW MacroDict (so we keep any macros defined in the header file) - %%NMacroDict = dict:store('FILE', {[], CurrFilename}, IncludedMacroDict), - NMacroDict = IncludedMacroDict, - - %% Continue with the original file - scan_and_parse(NRemainingText, CurrFilename, NLine, RevIncludeForms ++ RevForms, NMacroDict, IncludeSearchPath); - done -> - scan_and_parse([], CurrFilename, CurrLine, RevForms, MacroDict, IncludeSearchPath) - end. - -%% @private --spec scanner(Text :: 'eof' | string(), - Line :: integer() | {integer(), pos_integer()}, - MacroDict :: macro_dict()) -> - 'done' - | {'include', integer() | {integer(), pos_integer()}, 'eof' | string(), _} - | {'macro', integer() | {integer(), pos_integer()}, 'eof' | string(), macro_dict()} - | {'tokens', integer() | {integer(), pos_integer()}, 'eof' | string(), [any()]}. -scanner(Text, Line, MacroDict) -> - case erl_scan:tokens([], Text, Line) of - {done, {ok, Toks, NLine}, LeftOverChars} -> - case pre_proc(Toks, MacroDict) of - {tokens, NToks} -> {tokens, NLine, LeftOverChars, NToks}; - {macro, NMacroDict} -> {macro, NLine, LeftOverChars, NMacroDict}; - {include, Filename} -> {include, NLine, LeftOverChars, Filename} - end; - {more, _Continuation} -> - %% This is supposed to mean "term is not yet complete" (i.e. a '.' has - %% not been reached yet). - %% However, for some bizarre reason we also get this if there is a comment after the final '.' in a file. - %% So we check to see if Text only consists of comments. - case is_only_comments(Text) of - true -> - done; - false -> - throw({incomplete_term, Text, Line}) - end - end. - -%% @private --spec is_only_comments('eof' | string()) -> boolean(). -is_only_comments(Text) -> is_only_comments(Text, not_in_comment). - -%% @private --spec is_only_comments('eof' | string(), 'in_comment' | 'not_in_comment') -> boolean(). -is_only_comments([], _) -> true; -is_only_comments([$ |T], not_in_comment) -> is_only_comments(T, not_in_comment); % skipping whitspace outside of comment -is_only_comments([$\t |T], not_in_comment) -> is_only_comments(T, not_in_comment); % skipping whitspace outside of comment -is_only_comments([$\n |T], not_in_comment) -> is_only_comments(T, not_in_comment); % skipping whitspace outside of comment -is_only_comments([$% |T], not_in_comment) -> is_only_comments(T, in_comment); % found start of a comment -is_only_comments(_, not_in_comment) -> false; -% found any significant char NOT in a comment -is_only_comments([$\n |T], in_comment) -> is_only_comments(T, not_in_comment); % found end of a comment -is_only_comments([_ |T], in_comment) -> is_only_comments(T, in_comment). % skipping over in-comment chars - -%% @doc 'pre-proc' -%% have to implement a subset of the pre-processor, since epp insists -%% on running on a file. Only handles 2 cases; -%% -define(MACRO, something). -%% -define(MACRO(VAR1, VARN), {stuff, VAR1, more, stuff, VARN, extra, stuff}). -%% @private --spec pre_proc([{_, _} | {_, _, _}], macro_dict()) -> {'include', _} | {'macro', macro_dict()} | {'tokens', [any()]}. -pre_proc([{'-', _}, {atom, _, define}, {'(', _}, {_, _, Name}|DefToks], MacroDict) -> - false = dict:is_key(Name, MacroDict), - case DefToks of - [{', ', _} | Macro] -> - {macro, dict:store(Name, {[], macro_body_def(Macro, [])}, MacroDict)}; - [{'(', _} | Macro] -> - {macro, dict:store(Name, macro_params_body_def(Macro, []), MacroDict)} - end; -pre_proc([{'-', _}, {atom, _, include}, {'(', _}, {string, _, Filename}, {')', _}, {dot, _}], _MacroDict) -> - {include, Filename}; -pre_proc(Toks, MacroDict) -> - {tokens, subst_macros(Toks, MacroDict)}. - -%% @private --spec macro_params_body_def(Tokens :: [{_, _} | {_, _, _}, ...], - RevParams :: [any()] - ) -> {[any()], [{_, _} | {_, _, _}]}. -macro_params_body_def([{')', _}, {', ', _} | Toks], RevParams) -> - {reverse(RevParams), macro_body_def(Toks, [])}; -macro_params_body_def([{var, _, Param} | Toks], RevParams) -> - macro_params_body_def(Toks, [Param | RevParams]); -macro_params_body_def([{', ', _}, {var, _, Param} | Toks], RevParams) -> - macro_params_body_def(Toks, [Param | RevParams]). - -%% @private --spec macro_body_def(Tokens :: [{_, _} | {_, _, _}, ...], - RevMacroBodyTokens :: [{_, _} | {_, _, _}] - ) -> [{_, _} | {_, _, _}]. -macro_body_def([{')', _}, {dot, _}], RevMacroBodyToks) -> - reverse(RevMacroBodyToks); -macro_body_def([Tok|Toks], RevMacroBodyToks) -> - macro_body_def(Toks, [Tok | RevMacroBodyToks]). - -%% @private --spec subst_macros(Toks :: [{_, _} | {_, _, _}], MacroDict :: macro_dict()) -> [any()]. -subst_macros(Toks, MacroDict) -> - reverse(subst_macros_rev(Toks, MacroDict, [])). - -%% @doc Returns a reversed list of tokens -%% @private --spec subst_macros_rev(Tokens :: maybe_improper_list(), - MacroDict :: macro_dict(), - RevOutToks :: [any()]) -> [any()]. -subst_macros_rev([{'?', _}, {_, LineNum, 'LINE'} | Toks], MacroDict, RevOutToks) -> - %% special-case for ?LINE, to avoid creating a new MacroDict for every line in the source file - subst_macros_rev(Toks, MacroDict, [{integer, LineNum, LineNum}] ++ RevOutToks); -subst_macros_rev([{'?', _}, {_, _, Name}, {'(', _} = Paren | Toks], MacroDict, RevOutToks) -> - case dict:fetch(Name, MacroDict) of - {[], MacroValue} -> - %% This macro does not have any vars, so ignore the fact that the invocation is followed by "(...stuff" - %% Recursively expand any macro calls inside this macro's value - %% TODO: avoid infinite expansion due to circular references (even indirect ones) - RevExpandedOtherMacrosToks = subst_macros_rev(MacroValue, MacroDict, []), - subst_macros_rev([Paren|Toks], MacroDict, RevExpandedOtherMacrosToks ++ RevOutToks); - ParamsAndBody -> - %% This macro does have vars. - %% Collect all of the passe arguments, in an ordered list - {NToks, Arguments} = subst_macros_get_args(Toks, []), - %% Expand the varibles - ExpandedParamsToks = subst_macros_subst_args_for_vars(ParamsAndBody, Arguments), - %% Recursively expand any macro calls inside this macro's value - %% TODO: avoid infinite expansion due to circular references (even indirect ones) - RevExpandedOtherMacrosToks = subst_macros_rev(ExpandedParamsToks, MacroDict, []), - subst_macros_rev(NToks, MacroDict, RevExpandedOtherMacrosToks ++ RevOutToks) - end; -subst_macros_rev([{'?', _}, {_, _, Name} | Toks], MacroDict, RevOutToks) -> - %% This macro invocation does not have arguments. - %% Therefore the definition should not have parameters - {[], MacroValue} = dict:fetch(Name, MacroDict), - - %% Recursively expand any macro calls inside this macro's value - %% TODO: avoid infinite expansion due to circular references (even indirect ones) - RevExpandedOtherMacrosToks = subst_macros_rev(MacroValue, MacroDict, []), - subst_macros_rev(Toks, MacroDict, RevExpandedOtherMacrosToks ++ RevOutToks); -subst_macros_rev([Tok|Toks], MacroDict, RevOutToks) -> - subst_macros_rev(Toks, MacroDict, [Tok|RevOutToks]); -subst_macros_rev([], _MacroDict, RevOutToks) -> RevOutToks. - -%% @private --spec subst_macros_get_args(Toks :: nonempty_maybe_improper_list(), - RevArgs :: [any()]) -> {_, [any()]}. -subst_macros_get_args([{')', _} | Toks], RevArgs) -> - {Toks, reverse(RevArgs)}; -subst_macros_get_args([{', ', _}, {var, _, ArgName} | Toks], RevArgs) -> - subst_macros_get_args(Toks, [ArgName| RevArgs]); -subst_macros_get_args([{var, _, ArgName} | Toks], RevArgs) -> - subst_macros_get_args(Toks, [ArgName | RevArgs]). - -%% @private --spec subst_macros_subst_args_for_vars({[any()], _}, [any()]) -> any(). -subst_macros_subst_args_for_vars({[], BodyToks}, []) -> - BodyToks; -subst_macros_subst_args_for_vars({[Param | Params], BodyToks}, [Arg|Args]) -> - NBodyToks = keyreplace(Param, 3, BodyToks, {var, 1, Arg}), - subst_macros_subst_args_for_vars({Params, NBodyToks}, Args). - -%% @private --spec read_include_file(Filename :: file:name(), - IncludeSearchPath :: [file:name(), ...] - ) -> [byte()]. -read_include_file(Filename, IncludeSearchPath) -> - case file:path_open(IncludeSearchPath, Filename, [read, raw, binary]) of - {ok, IoDevice, FullName} -> - {ok, Data} = file:read(IoDevice, filelib:file_size(FullName)), - file:close(IoDevice), - binary_to_list(Data); - {error, Reason} -> - throw({failed_to_read_include_file, Reason, Filename, IncludeSearchPath}) - end. diff --git a/big_tests/tests/acc_e2e_SUITE_data/acc_test_helper.erl b/big_tests/src/mim_helpers/acc_test_helper.erl similarity index 91% rename from big_tests/tests/acc_e2e_SUITE_data/acc_test_helper.erl rename to big_tests/src/mim_helpers/acc_test_helper.erl index e73d021f03a..c4bf9d601ec 100644 --- a/big_tests/tests/acc_e2e_SUITE_data/acc_test_helper.erl +++ b/big_tests/src/mim_helpers/acc_test_helper.erl @@ -2,6 +2,7 @@ -author("bartek"). -compile([export_all, nowarn_export_all]). +-include_lib("exml/include/exml.hrl"). -spec test_save_acc(Acc, Params, Extra) -> {ok, Acc} when Acc :: mongoose_acc:t(), @@ -91,11 +92,9 @@ check_acc(Acc, stripped) -> Params :: map(), Extra :: map(). alter_message({From, To, Acc, Packet}, _, _) -> - % Not using #xmlel as it causes some strange error in dynamic compilation - {xmlel, PName, PAttrs, PCh} = Packet, - NewBody = {xmlel, <<"body">>, [], [{xmlcdata, <<"bye">> }]}, - PCh2 = lists:keyreplace(<<"body">>, 2, PCh, NewBody), - NewAcc = {From, To, Acc, {xmlel, PName, PAttrs, PCh2}}, + NewBody = #xmlel{name = <<"body">>, children = [#xmlcdata{content = <<"bye">>}]}, + NewChildren = lists:keyreplace(<<"body">>, 2, Packet#xmlel.children, NewBody), + NewAcc = {From, To, Acc, Packet#xmlel{children = NewChildren}}, {ok, NewAcc}. cached_my_jid(User, Acc) -> diff --git a/big_tests/src/mim_helpers/amp_test_helper.erl b/big_tests/src/mim_helpers/amp_test_helper.erl new file mode 100644 index 00000000000..161db023ce1 --- /dev/null +++ b/big_tests/src/mim_helpers/amp_test_helper.erl @@ -0,0 +1,11 @@ +-module(amp_test_helper). +-compile([export_all, nowarn_export_all]). + +setup_meck() -> + meck:expect(ranch_tcp, send, fun ranch_tcp_send/2). + +ranch_tcp_send(Socket, Data) -> + case catch binary:match(Data, <<"Recipient connection breaks">>) of + {N, _} when is_integer(N) -> {error, simulated}; + _ -> meck:passthrough([Socket, Data]) + end. diff --git a/big_tests/src/mim_helpers/mod_event_pusher_http_custom.erl b/big_tests/src/mim_helpers/mod_event_pusher_http_custom.erl new file mode 100644 index 00000000000..f775f6b39c4 --- /dev/null +++ b/big_tests/src/mim_helpers/mod_event_pusher_http_custom.erl @@ -0,0 +1,14 @@ +-module(mod_event_pusher_http_custom). +-export([should_make_req/6, prepare_body/7, prepare_headers/7]). + +should_make_req(Acc, _, _, _, _, _) -> + case mongoose_acc:stanza_name(Acc) of + <<"message">> -> true; + _ -> false + end. + +prepare_headers(_, _, _, _, _, _, _) -> + mod_event_pusher_http_defaults:prepare_headers(x, x, x, x, x, x, x). + +prepare_body(_Acc, Dir, _Host, Message, _Sender, _Receiver, _Opts) -> + <<(atom_to_binary(Dir, utf8))/binary, $-, Message/binary>>. diff --git a/big_tests/src/mim_helpers/mod_event_pusher_http_custom_2.erl b/big_tests/src/mim_helpers/mod_event_pusher_http_custom_2.erl new file mode 100644 index 00000000000..c88bcd33c02 --- /dev/null +++ b/big_tests/src/mim_helpers/mod_event_pusher_http_custom_2.erl @@ -0,0 +1,16 @@ +-module(mod_event_pusher_http_custom_2). +-export([should_make_req/6, prepare_body/7, prepare_headers/7]). + +should_make_req(Acc, out, _, _, _, _) -> + case mongoose_acc:stanza_name(Acc) of + <<"message">> -> true; + _ -> false + end; + +should_make_req(_, in, _, _, _, _) -> false. + +prepare_headers(_, _, _, _, _, _, _) -> + mod_event_pusher_http_defaults:prepare_headers(x, x, x, x, x, x, x). + +prepare_body(_Acc, Dir, _Host, Message, _Sender, _Receiver, _Opts) -> + <<$2, $-, (atom_to_binary(Dir, utf8))/binary, $-, Message/binary>>. diff --git a/big_tests/src/mim_helpers/tcp_listener_helper.erl b/big_tests/src/mim_helpers/tcp_listener_helper.erl new file mode 100644 index 00000000000..eb4683e9c2d --- /dev/null +++ b/big_tests/src/mim_helpers/tcp_listener_helper.erl @@ -0,0 +1,12 @@ +-module(tcp_listener_helper). +-compile([export_all, nowarn_export_all]). + +setup_meck() -> + meck:expect(mongoose_tcp_listener, read_connection_details, fun read_connection_details/2). + +read_connection_details(Socket, Opts) -> + persistent_term:put(tcp_listener_helper_info, {Socket, self()}), + gen_tcp:close(Socket), + Result = meck:passthrough([Socket, Opts]), + persistent_term:put(tcp_listener_helper_result, Result), + Result. diff --git a/big_tests/tests/acc_e2e_SUITE.erl b/big_tests/tests/acc_e2e_SUITE.erl index 5a69df33339..a6fc54d6494 100644 --- a/big_tests/tests/acc_e2e_SUITE.erl +++ b/big_tests/tests/acc_e2e_SUITE.erl @@ -63,8 +63,8 @@ suite() -> %%-------------------------------------------------------------------- init_per_suite(Config) -> - {Mod, Code} = dynamic_compile:from_string(acc_test_helper_code(Config)), - rpc(mim(), code, load_binary, [Mod, "acc_test_helper.erl", Code]), + {Module, Binary, Filename} = code:get_object_code(acc_test_helper) , + rpc(mim(), code, load_binary, [Module, Filename, Binary]), recreate_table(), escalus:init_per_suite(Config). @@ -163,12 +163,6 @@ filter_local_packet_uses_recipient_values(Config) -> %%-------------------------------------------------------------------- -acc_test_helper_code(Config) -> - Dir = proplists:get_value(mim_data_dir, Config), - F = filename:join(Dir, "acc_test_helper.erl"), - {ok, Code} = file:read_file(F), - binary_to_list(Code). - add_handler(Hook, F, Seq) -> rpc(mim(), gen_hook, add_handler, handler(Hook, F, Seq)). diff --git a/big_tests/tests/accounts_SUITE.erl b/big_tests/tests/accounts_SUITE.erl index 1f7b27ba9dc..c698e4d66eb 100644 --- a/big_tests/tests/accounts_SUITE.erl +++ b/big_tests/tests/accounts_SUITE.erl @@ -428,7 +428,7 @@ has_registered_element(Stanza) -> bad_cancelation_stanza() -> escalus_stanza:iq(<<"set">>, [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, <<"jabber:iq:register">>}], + attrs = #{<<"xmlns">> => <<"jabber:iq:register">>}, children = [#xmlel{name = <<"remove">>}, %% The element is not the only child element of the %% element. diff --git a/big_tests/tests/amp_big_SUITE.erl b/big_tests/tests/amp_big_SUITE.erl index df2123a3607..a0977f1936c 100644 --- a/big_tests/tests/amp_big_SUITE.erl +++ b/big_tests/tests/amp_big_SUITE.erl @@ -115,23 +115,12 @@ deliver_test_cases(drop) -> init_per_suite(Config) -> ConfigWithHooks = [{ct_hooks, [{multiple_config_cth, fun tests_with_config/1}]} | Config], - {Mod, Code} = dynamic_compile:from_string(amp_test_helper_code()), - rpc(mim(), code, load_binary, [Mod, "amp_test_helper.erl", Code]), + {Module, Binary, Filename} = code:get_object_code(amp_test_helper) , + rpc(mim(), code, load_binary, [Module, Filename, Binary]), setup_meck(suite), instrument_helper:start(declared_events()), escalus:init_per_suite(ConfigWithHooks). -amp_test_helper_code() -> - "-module(amp_test_helper).\n" - "-compile([export_all, nowarn_export_all]).\n" - "setup_meck() ->\n" - " meck:expect(ranch_tcp, send, fun ranch_tcp_send/2).\n" - "ranch_tcp_send(Socket, Data) ->\n" - " case catch binary:match(Data, <<\"Recipient connection breaks\">>) of\n" - " {N, _} when is_integer(N) -> {error, simulated};\n" - " _ -> meck:passthrough([Socket, Data])\n" - " end.\n". - declared_events() -> [ % tested by privacy helpers {mod_privacy_set, #{host_type => host_type()}}, @@ -885,15 +874,15 @@ amp_el([]) -> throw("cannot build with no rules!"); amp_el(Rules) -> #xmlel{name = <<"amp">>, - attrs = [{<<"xmlns">>, ns_amp()}], + attrs = #{<<"xmlns">> => ns_amp()}, children = [ rule_el(R) || R <- Rules ]}. rule_el({Condition, Value, Action}) -> check_rules(Condition, Value, Action), #xmlel{name = <<"rule">> - , attrs = [{<<"condition">>, a2b(Condition)} - , {<<"value">>, a2b(Value)} - , {<<"action">>, a2b(Action)}]}. + , attrs = #{<<"condition">> => a2b(Condition) + , <<"value">> => a2b(Value) + , <<"action">> => a2b(Action)}}. %% @TODO: Move me out to escalus_pred %%%%%%%%%%%% %%%%%%%%% XML predicates %%%%% %%%%%%%%%%%%%%%%%%% diff --git a/big_tests/tests/bind2_SUITE.erl b/big_tests/tests/bind2_SUITE.erl index 6a42b8f33a3..361a8a0815f 100644 --- a/big_tests/tests/bind2_SUITE.erl +++ b/big_tests/tests/bind2_SUITE.erl @@ -97,7 +97,7 @@ auth_and_bind_ignores_invalid_resource_and_generates_a_new_one(Config) -> auth_and_bind_to_random_resource(Config) -> Steps = [start_new_user, {?MODULE, auth_and_bind}, receive_features, has_no_more_stanzas], #{answer := Success} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"success">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Success), + ?assertMatch(#xmlel{name = <<"success">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Success), Bound = exml_query:path(Success, [{element_with_ns, <<"bound">>, ?NS_BIND_2}]), ?assertNotEqual(undefined, Bound), Identifier = exml_query:path(Success, [{element, <<"authorization-identifier">>}, cdata]), @@ -107,7 +107,7 @@ auth_and_bind_to_random_resource(Config) -> auth_and_bind_do_not_expose_user_agent_id_in_client(Config) -> Steps = [start_new_user, {?MODULE, auth_and_bind_with_user_agent_uuid}, receive_features, has_no_more_stanzas], #{answer := Success, uuid := Uuid} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"success">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Success), + ?assertMatch(#xmlel{name = <<"success">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Success), Bound = exml_query:path(Success, [{element_with_ns, <<"bound">>, ?NS_BIND_2}]), ?assertNotEqual(undefined, Bound), Identifier = exml_query:path(Success, [{element, <<"authorization-identifier">>}, cdata]), @@ -117,7 +117,7 @@ auth_and_bind_do_not_expose_user_agent_id_in_client(Config) -> auth_and_bind_contains_client_tag(Config) -> Steps = [start_new_user, {?MODULE, auth_and_bind_with_tag}, receive_features, has_no_more_stanzas], #{answer := Success, tag := Tag} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"success">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Success), + ?assertMatch(#xmlel{name = <<"success">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Success), Bound = exml_query:path(Success, [{element_with_ns, <<"bound">>, ?NS_BIND_2}]), ?assertNotEqual(undefined, Bound), Identifier = exml_query:path(Success, [{element, <<"authorization-identifier">>}, cdata]), @@ -154,7 +154,7 @@ stream_resumption_enable_sm_on_bind(Config) -> {?MODULE, auth_and_bind_with_sm_enabled}, receive_features, has_no_more_stanzas], #{answer := Success} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"success">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Success), + ?assertMatch(#xmlel{name = <<"success">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Success), Enabled = exml_query:path(Success, [{element_with_ns, <<"bound">>, ?NS_BIND_2}, {element_with_ns, <<"enabled">>, ?NS_STREAM_MGNT_3}]), ?assertNotEqual(undefined, Enabled). @@ -165,7 +165,7 @@ stream_resumption_enable_sm_on_bind_with_resume(Config) -> {?MODULE, auth_and_bind_with_sm_resume_enabled}, receive_features, has_no_more_stanzas], #{answer := Success} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"success">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Success), + ?assertMatch(#xmlel{name = <<"success">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Success), Enabled = exml_query:path(Success, [{element_with_ns, <<"bound">>, ?NS_BIND_2}, {element_with_ns, <<"enabled">>, ?NS_STREAM_MGNT_3}]), ?assertNotEqual(undefined, Enabled). @@ -175,7 +175,7 @@ stream_resumption_failing_does_bind_and_contains_sm_status(Config) -> {?MODULE, auth_and_bind_with_resumption_unknown_smid}, receive_features, has_no_more_stanzas], #{answer := Success, tag := Tag} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"success">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Success), + ?assertMatch(#xmlel{name = <<"success">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Success), Bound = exml_query:path(Success, [{element_with_ns, <<"bound">>, ?NS_BIND_2}]), ?assertNotEqual(undefined, Bound), Resumed = exml_query:path(Success, [{element_with_ns, <<"failed">>, ?NS_STREAM_MGNT_3}]), @@ -189,7 +189,7 @@ stream_resumption_overrides_bind_request(Config) -> Steps = [create_user, buffer_messages_and_die, connect_tls, start_stream_get_features, {?MODULE, auth_and_bind_with_resumption}, has_no_more_stanzas], #{answer := Success, smid := SMID} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"success">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Success), + ?assertMatch(#xmlel{name = <<"success">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Success), Resumed = exml_query:path(Success, [{element_with_ns, <<"resumed">>, ?NS_STREAM_MGNT_3}]), ?assert(escalus_pred:is_sm_resumed(SMID, Resumed)). @@ -281,7 +281,7 @@ receive_message_carbon_arrives( plain_auth(_Config, Client, Data, BindElems, Extra) -> InitEl = sasl2_helper:plain_auth_initial_response(Client), BindEl = #xmlel{name = <<"bind">>, - attrs = [{<<"xmlns">>, ?NS_BIND_2}], + attrs = #{<<"xmlns">> => ?NS_BIND_2}, children = BindElems}, Authenticate = auth_elem(<<"PLAIN">>, [InitEl, BindEl | Extra]), escalus:send(Client, Authenticate), @@ -298,7 +298,7 @@ start_peer(Config, Client, Data) -> %% XML helpers auth_elem(Mech, Children) -> #xmlel{name = <<"authenticate">>, - attrs = [{<<"xmlns">>, ?NS_SASL_2}, {<<"mechanism">>, Mech}], + attrs = #{<<"xmlns">> => ?NS_SASL_2, <<"mechanism">> => Mech}, children = Children}. bind_tag(Tag) -> @@ -306,7 +306,7 @@ bind_tag(Tag) -> enable_carbons_el() -> #xmlel{name = <<"enable">>, - attrs = [{<<"xmlns">>, ?NS_CARBONS_2}]}. + attrs = #{<<"xmlns">> => ?NS_CARBONS_2}}. good_user_agent_elem(Uuid) -> user_agent_elem(Uuid, <<"cool-xmpp-client">>, <<"latest-and-greatest-device">>). @@ -316,7 +316,7 @@ user_agent_elem(Id, Software, Device) -> || Value <- [Software], Value =/= undefined ], DeviEl = [#xmlel{name = <<"device">>, children = [#xmlcdata{content = Value}]} || Value <- [Device], Value =/= undefined ], - Attrs = [ {<<"id">>, Value} || Value <- [Id], Value =/= undefined ], + Attrs = #{<<"id">> => Value || Value <- [Id], Value =/= undefined}, #xmlel{name = <<"user-agent">>, attrs = Attrs, children = SoftEl ++ DeviEl}. check_var(InlineFeatures, NS) -> diff --git a/big_tests/tests/bosh_SUITE.erl b/big_tests/tests/bosh_SUITE.erl index abebaf23381..e7a00d5d8a8 100644 --- a/big_tests/tests/bosh_SUITE.erl +++ b/big_tests/tests/bosh_SUITE.erl @@ -209,7 +209,7 @@ reject_connection_when_mod_bosh_is_disabled(Config) -> {{<<"200">>, <<"OK">>}, _Headers, RespBody, _, _} = Result, {ok, #xmlel{attrs = RespAttrs}} = exml:parse(RespBody), - ?assertMatch(#{<<"type">> := <<"terminate">>}, maps:from_list(RespAttrs)), + ?assertMatch(#{<<"type">> := <<"terminate">>}, RespAttrs), ?assertEqual([], get_bosh_sessions()), fusco_cp:stop(Client). @@ -217,14 +217,14 @@ do_not_accept_0_hold_value(Config) -> {Domain, Path, Client} = get_fusco_connection(Config), Rid = rand:uniform(1000000), Body0 = escalus_bosh:session_creation_body(2, <<"1.0">>, <<"en">>, Rid, Domain, nil), - #xmlel{attrs = Attrs0} = Body0, - Attrs = lists:keyreplace(<<"hold">>, 1, Attrs0, {<<"hold">>, <<"0">>}), + Attrs0 = Body0#xmlel.attrs, + Attrs = Attrs0#{<<"hold">> := <<"0">>}, Body = Body0#xmlel{attrs = Attrs}, Result = fusco_request(Client, <<"POST">>, Path, exml:to_iolist(Body)), {{<<"200">>, <<"OK">>}, _Headers, RespBody, _, _} = Result, {ok, #xmlel{attrs = RespAttrs}} = exml:parse(RespBody), - ?assertMatch(#{<<"type">> := <<"terminate">>}, maps:from_list(RespAttrs)), + ?assertMatch(#{<<"type">> := <<"terminate">>}, RespAttrs), ?assertEqual([], get_bosh_sessions()), fusco_cp:stop(Client). @@ -232,22 +232,22 @@ accept_higher_hold_value(Config) -> {Domain, Path, Client} = get_fusco_connection(Config), Rid = rand:uniform(1000000), Body0 = escalus_bosh:session_creation_body(2, <<"1.0">>, <<"en">>, Rid, Domain, nil), - #xmlel{attrs = Attrs0} = Body0, - Attrs = lists:keyreplace(<<"hold">>, 1, Attrs0, {<<"hold">>, <<"2">>}), + Attrs0 = Body0#xmlel.attrs, + Attrs = Attrs0#{<<"hold">> := <<"2">>}, Body = Body0#xmlel{attrs = Attrs}, Result = fusco_request(Client, <<"POST">>, Path, exml:to_iolist(Body)), {{<<"200">>, <<"OK">>}, _Headers, RespBody, _, _} = Result, {ok, #xmlel{attrs = RespAttrs}} = exml:parse(RespBody), %% Server returns its hold value, which is 1 - #{<<"hold">> := <<"1">>, <<"sid">> := SID} = maps:from_list(RespAttrs), + #{<<"hold">> := <<"1">>, <<"sid">> := SID} = RespAttrs, ?assertMatch([_], get_bosh_sessions()), TerminateBody = escalus_bosh:session_termination_body(Rid + 1, SID), Res2 = fusco_request(Client, <<"POST">>, Path, exml:to_iolist(TerminateBody)), {{<<"200">>, <<"OK">>}, _, RespBody2, _, _} = Res2, {ok, #xmlel{attrs = RespAttrs2}} = exml:parse(RespBody2), - case maps:from_list(RespAttrs2) of + case RespAttrs2 of #{<<"type">> := <<"terminate">>} -> ok; #{<<"sid">> := SID} -> @@ -256,7 +256,7 @@ accept_higher_hold_value(Config) -> Res3 = fusco_request(Client, <<"POST">>, Path, exml:to_iolist(EmptyBody)), {{<<"200">>, <<"OK">>}, _, RespBody3, _, _} = Res3, {ok, #xmlel{attrs = RespAttrs3}} = exml:parse(RespBody3), - ?assertMatch(#{<<"type">> := <<"terminate">>}, maps:from_list(RespAttrs3)) + ?assertMatch(#{<<"type">> := <<"terminate">>}, RespAttrs3) end, ?assertEqual([], get_bosh_sessions()), fusco_cp:stop(Client). @@ -897,8 +897,7 @@ wait_for_stanza(Client) -> ack_body(Body, Rid) -> Attrs = Body#xmlel.attrs, - Ack = {<<"ack">>, integer_to_binary(Rid)}, - NewAttrs = lists:keystore(<<"ack">>, 1, Attrs, Ack), + NewAttrs = Attrs#{<<"ack">> => integer_to_binary(Rid)}, Body#xmlel{attrs = NewAttrs}. set_client_acks(SessionPid, Enabled) -> diff --git a/big_tests/tests/carboncopy_helper.erl b/big_tests/tests/carboncopy_helper.erl index b66873005df..12c0815b6ce 100644 --- a/big_tests/tests/carboncopy_helper.erl +++ b/big_tests/tests/carboncopy_helper.erl @@ -36,8 +36,8 @@ is_forwarded_message(From, To, Stanza) -> is_message_from_to(From, To, #xmlel{attrs = Attrs} = Stanza) -> escalus_pred:is_message(Stanza) andalso - escalus_compat:bin(From) == proplists:get_value(<<"from">>, Attrs) andalso - escalus_compat:bin(To) == proplists:get_value(<<"to">>, Attrs). + escalus_compat:bin(From) == maps:get(<<"from">>, Attrs, undefined) andalso + escalus_compat:bin(To) == maps:get(<<"to">>, Attrs, undefined). chat_message_with_body(#{to := User, body := Body}) -> escalus_stanza:chat_to(User, Body). @@ -48,25 +48,25 @@ normal_message_with_body(#{to := User, body := Body}) -> normal_message_with_receipt(#{to := User}) -> Msg = #xmlel{ name = <<"message">>, - attrs = [ - {<<"type">>, <<"normal">>}, - {<<"from">>, escalus_utils:get_jid(User)}, - {<<"id">>, escalus_stanza:id()} - ] + attrs = #{ + <<"type">> => <<"normal">>, + <<"from">> => escalus_utils:get_jid(User), + <<"id">> => escalus_stanza:id() + } }, escalus_stanza:receipt_conf(Msg). normal_message_with_csn(#{to := User}) -> #xmlel{ name = <<"message">>, - attrs = [ - {<<"type">>, <<"normal">>}, - {<<"to">>, escalus_utils:get_jid(User)} - ], + attrs = #{ + <<"type">> => <<"normal">>, + <<"to">> => escalus_utils:get_jid(User) + }, children = [ #xmlel{ name = <<"stateName">>, - attrs = [{<<"xmlns">>, ?NS_CHATSTATES}] + attrs = #{<<"xmlns">> => ?NS_CHATSTATES} } ] }. diff --git a/big_tests/tests/component_helper.erl b/big_tests/tests/component_helper.erl index 7f2cacbe946..2dbbd1bf5c5 100644 --- a/big_tests/tests/component_helper.erl +++ b/big_tests/tests/component_helper.erl @@ -6,7 +6,7 @@ disconnect_component/2, disconnect_components/2, connect_component_subdomain/1, - get_components/1, get_components/2, get_components/3, + get_components/1, get_components/2, get_components/3, spec/2, common/1, common/2, @@ -71,20 +71,19 @@ component_start_stream(Conn = #client{props = Props}, []) -> ct:log("received~n~p~n", [StreamStartRep]), #xmlstreamstart{attrs = Attrs} = StreamStartRep, - Id = proplists:get_value(<<"id">>, Attrs), + Id = maps:get(<<"id">>, Attrs, undefined), {Conn#client{props = [{sid, Id} | Props]}, []}. component_stream_start(Component, IsSubdomain) -> - Attrs1 = [{<<"to">>, Component}, - {<<"xmlns">>, <<"jabber:component:accept">>}, - {<<"xmlns:stream">>, - <<"http://etherx.jabber.org/streams">>}], + Attrs1 = #{<<"to">> => Component, + <<"xmlns">> => <<"jabber:component:accept">>, + <<"xmlns:stream">> => <<"http://etherx.jabber.org/streams">>}, Attrs2 = case IsSubdomain of false -> Attrs1; true -> - [{<<"is_subdomain">>, <<"true">>}|Attrs1] + Attrs1#{<<"is_subdomain">> => <<"true">>} end, #xmlstreamstart{name = <<"stream:stream">>, attrs = Attrs2}. @@ -119,7 +118,7 @@ component_start_stream_subdomain(Conn = #client{props = Props}, []) -> ct:log("received~n~p~n", [StreamStartRep]), #xmlstreamstart{attrs = Attrs} = StreamStartRep, - Id = proplists:get_value(<<"id">>, Attrs), + Id = maps:get(<<"id">>, Attrs, undefined), {Conn#client{props = [{sid, Id}|Props]}, []}. diff --git a/big_tests/tests/connect_SUITE.erl b/big_tests/tests/connect_SUITE.erl index 01ad0efe855..36100e96cf1 100644 --- a/big_tests/tests/connect_SUITE.erl +++ b/big_tests/tests/connect_SUITE.erl @@ -506,7 +506,7 @@ auth_bind_pipelined_auth_failure(Config) -> %% Auth response AuthResponse = escalus_connection:get_stanza(Conn, auth_response), - ?assertMatch(#xmlel{name = <<"failure">>, attrs = [{<<"xmlns">>, ?NS_SASL}]}, AuthResponse). + ?assertMatch(#xmlel{name = <<"failure">>, attrs = #{<<"xmlns">> := ?NS_SASL}}, AuthResponse). auth_bind_pipelined_starttls_skipped_error(Config) -> UserSpec = [{parser_opts, [{start_tag, <<"stream:stream">>}]} @@ -793,7 +793,7 @@ start_stream_pre_xmpp_1_0(Conn = #client{props = Props}, UnusedFeatures) -> escalus:send(Conn, stream_start_pre_xmpp_1_0(escalus_users:get_server([], Props))), #xmlstreamstart{attrs = StreamAttrs} = StreamStart = escalus:wait_for_stanza(Conn), escalus:assert(is_stream_start, StreamStart), - {<<"id">>, StreamID} = lists:keyfind(<<"id">>, 1, StreamAttrs), + StreamID = maps:get(<<"id">>, StreamAttrs), {Conn#client{props = [{stream_id, StreamID} | Props]}, UnusedFeatures}. stream_start_pre_xmpp_1_0(To) -> diff --git a/big_tests/tests/csi_helper.erl b/big_tests/tests/csi_helper.erl index feb66f6b48c..b4b99f2a89f 100644 --- a/big_tests/tests/csi_helper.erl +++ b/big_tests/tests/csi_helper.erl @@ -33,4 +33,4 @@ send_msgs(From, To, Msgs) -> csi_stanza(Name) -> #xmlel{name = Name, - attrs = [{<<"xmlns">>, ?NS_CSI}]}. + attrs = #{<<"xmlns">> => ?NS_CSI}}. diff --git a/big_tests/tests/domain_removal_SUITE.erl b/big_tests/tests/domain_removal_SUITE.erl index 9618b4f498e..c9152d7559a 100644 --- a/big_tests/tests/domain_removal_SUITE.erl +++ b/big_tests/tests/domain_removal_SUITE.erl @@ -574,7 +574,7 @@ block_muclight_user(Bob, Alice) -> my_banana(NS) -> #xmlel{ name = <<"my_element">>, - attrs = [{<<"xmlns">>, NS}], + attrs = #{<<"xmlns">> => NS}, children = [#xmlcdata{content = <<"banana">>}]}. get_private_data(Elem, Tag, NS) -> diff --git a/big_tests/tests/extdisco_SUITE.erl b/big_tests/tests/extdisco_SUITE.erl index d22cd89a1a4..c0c12a1526e 100644 --- a/big_tests/tests/extdisco_SUITE.erl +++ b/big_tests/tests/extdisco_SUITE.erl @@ -324,33 +324,33 @@ remove_external_services(Config) -> request_external_services(To) -> escalus_stanza:iq(To, <<"get">>, [#xmlel{name = <<"services">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:extdisco:2">>}]}]). + attrs = #{<<"xmlns">> => <<"urn:xmpp:extdisco:2">>}}]). request_external_services_with_type(To, Type) -> escalus_stanza:iq(To, <<"get">>, [#xmlel{name = <<"services">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:extdisco:2">>}, - {<<"type">>, Type}]}]). + attrs = #{<<"xmlns">> => <<"urn:xmpp:extdisco:2">>, + <<"type">> => Type}}]). request_external_services_credentials(To, Type, Host) -> escalus_stanza:iq(To, <<"get">>, [#xmlel{name = <<"credentials">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:extdisco:2">>}], + attrs = #{<<"xmlns">> => <<"urn:xmpp:extdisco:2">>}, children = [#xmlel{name = <<"service">>, - attrs = [{<<"host">>, Host}, - {<<"type">>, Type}]}]}]). + attrs = #{<<"host">> => Host, + <<"type">> => Type}}]}]). request_external_services_credentials_host_only(To, Host) -> escalus_stanza:iq(To, <<"get">>, [#xmlel{name = <<"credentials">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:extdisco:2">>}], + attrs = #{<<"xmlns">> => <<"urn:xmpp:extdisco:2">>}, children = [#xmlel{name = <<"service">>, - attrs = [{<<"host">>, Host}]}]}]). + attrs = #{<<"host">> => Host}}]}]). request_external_services_incorrect(To) -> escalus_stanza:iq(To, <<"get">>, [#xmlel{name = <<"incorrect">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:extdisco:2">>}]}]). + attrs = #{<<"xmlns">> => <<"urn:xmpp:extdisco:2">>}}]). get_service_element(Result) -> Services = exml_query:subelement_with_ns(Result, ?NS_EXTDISCO), diff --git a/big_tests/tests/form_helper.erl b/big_tests/tests/form_helper.erl index c8e770ffd9f..f690af3f029 100644 --- a/big_tests/tests/form_helper.erl +++ b/big_tests/tests/form_helper.erl @@ -9,8 +9,8 @@ form(Spec) -> #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_DATA_FORMS}, - {<<"type">>, maps:get(type, Spec, <<"submit">>)}], + attrs = #{<<"xmlns">> => ?NS_DATA_FORMS, + <<"type">> => maps:get(type, Spec, <<"submit">>)}, children = lists:flatmap(fun(Item) -> form_children(Item, Spec) end, [ns, fields]) }. @@ -26,7 +26,7 @@ form_type_field(NS) when is_binary(NS) -> form_field(M) when is_map(M) -> Values = [form_field_value(Value) || Value <- maps:get(values, M, [])], - Attrs = [{atom_to_binary(K), V} || {K, V} <- maps:to_list(M), K =/= values], + Attrs = #{atom_to_binary(K) => V || K := V <- M, K =/= values}, #xmlel{name = <<"field">>, attrs = Attrs, children = Values}. form_field_value(Value) -> @@ -47,13 +47,14 @@ remove_fields(El, Name) -> modify_forms(El, fun(Form) -> [remove_form_field(Form, Name)] end). remove_form_attr(Form = #xmlel{attrs = Attrs}, AttrName) -> - Form#xmlel{attrs = proplists:delete(AttrName, Attrs)}. + Form#xmlel{attrs = maps:remove(AttrName, Attrs)}. remove_form_field(Form = #xmlel{children = Children}, FieldName) -> - NewChildren = lists:filter(fun(#xmlel{name = <<"field">>, attrs = Attrs}) -> - not lists:member({<<"var">>, FieldName}, Attrs); + NewChildren = lists:filter(fun(#xmlel{attrs = #{<<"var">> := Name}, + name = <<"field">>}) -> + FieldName =/= Name; (_) -> - true + true end, Children), Form#xmlel{children = NewChildren}. diff --git a/big_tests/tests/gdpr_SUITE.erl b/big_tests/tests/gdpr_SUITE.erl index 4c315a502a6..752d51a94ff 100644 --- a/big_tests/tests/gdpr_SUITE.erl +++ b/big_tests/tests/gdpr_SUITE.erl @@ -486,7 +486,7 @@ remove_private(Config) -> escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> %% Add some private data for Alice Element = #xmlel{name = <<"item">>, - attrs = [{<<"xmlns">>, <<"alice:private_remove:ns">>}], + attrs = #{<<"xmlns">> => <<"alice:private_remove:ns">>}, children = [#xmlcdata{ content = <<"Something to declare">> }]}, SetPrivateResult = escalus:send_and_wait(Alice, escalus_stanza:private_set(Element)), @@ -1761,12 +1761,12 @@ item_content(Data) -> item_content_xml(Data) -> #xmlel{name = <<"entry">>, - attrs = [{<<"xmlns">>, <<"http://www.w3.org/2005/Atom">>}], + attrs = #{<<"xmlns">> => <<"http://www.w3.org/2005/Atom">>}, children = [#xmlcdata{content = Data}]}. send_and_assert_private_stanza(User, NS, Content) -> XML = #xmlel{ name = <<"fingerprint">>, - attrs = [{<<"xmlns">>, NS}], + attrs = #{<<"xmlns">> => NS}, children = [#xmlcdata{ content = Content }]}, PrivateStanza = escalus_stanza:private_set(XML), escalus_client:send(User, PrivateStanza), diff --git a/big_tests/tests/graphql_muc_SUITE.erl b/big_tests/tests/graphql_muc_SUITE.erl index cdb41a82de4..beffb77e13c 100644 --- a/big_tests/tests/graphql_muc_SUITE.erl +++ b/big_tests/tests/graphql_muc_SUITE.erl @@ -1876,7 +1876,7 @@ assert_is_message_correct(RoomJID, SenderNick, Type, Text, ReceivedMessage) -> enter_room(RoomJID, User, Nick) -> JID = jid:to_binary(jid:replace_resource(RoomJID, Nick)), Pres = escalus_stanza:to(escalus_stanza:presence(<<"available">>, - [#xmlel{ name = <<"x">>, attrs=[{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}]}]), + [#xmlel{ name = <<"x">>, attrs=#{<<"xmlns">> => <<"http://jabber.org/protocol/muc">>}}]), JID), escalus:send(User, Pres), escalus:wait_for_stanza(User). diff --git a/big_tests/tests/graphql_muc_light_SUITE.erl b/big_tests/tests/graphql_muc_light_SUITE.erl index e7bdfd41a14..fa6e4fcc181 100644 --- a/big_tests/tests/graphql_muc_light_SUITE.erl +++ b/big_tests/tests/graphql_muc_light_SUITE.erl @@ -1885,7 +1885,7 @@ send_message_to_muc_room(User, Room, Body, Resource, Config) -> enter_muc_room(RoomJID, User, Nick) -> JID = jid:to_binary(jid:replace_resource(RoomJID, Nick)), Pres = escalus_stanza:to(escalus_stanza:presence(<<"available">>, - [#xmlel{ name = <<"x">>, attrs=[{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}]}]), + [#xmlel{ name = <<"x">>, attrs=#{<<"xmlns">> => <<"http://jabber.org/protocol/muc">>}}]), JID), escalus:send(User, Pres), escalus:wait_for_stanza(User). diff --git a/big_tests/tests/graphql_private_SUITE.erl b/big_tests/tests/graphql_private_SUITE.erl index dfcf551fb7b..abb13aef98b 100644 --- a/big_tests/tests/graphql_private_SUITE.erl +++ b/big_tests/tests/graphql_private_SUITE.erl @@ -228,8 +228,8 @@ no_user_error_get(Config) -> private_input() -> #xmlel{name = <<"my_element">>, - attrs = [{<<"xmlns">>, "alice:private:ns"}], - children = [{xmlcdata, <<"DATA">>}]}. + attrs = #{<<"xmlns">> => "alice:private:ns"}, + children = [#xmlcdata{content = <<"DATA">>}]}. % Admin private not configured test cases diff --git a/big_tests/tests/graphql_vcard_SUITE.erl b/big_tests/tests/graphql_vcard_SUITE.erl index be035249aed..e2878574beb 100644 --- a/big_tests/tests/graphql_vcard_SUITE.erl +++ b/big_tests/tests/graphql_vcard_SUITE.erl @@ -152,7 +152,7 @@ user_get_their_vcard(Config) -> user_get_their_vcard(Config, Alice) -> Client1Fields = [{<<"FN">>, <<"TESTNAME">>}, {<<"EMAIL">>, [{<<"USERID">>, <<"TESTEMAIL">>}, - {<<"HOME">>, []}, {"WORK", []}]}, {<<"EMAIL">>, [{<<"USERID">>, <<"TESTEMAIL2">>}, + {<<"HOME">>, []}, {<<"WORK">>, []}]}, {<<"EMAIL">>, [{<<"USERID">>, <<"TESTEMAIL2">>}, {<<"HOME">>, []}]}], ExpectedResult = #{<<"formattedName">> => <<"TESTNAME">>, <<"email">> => [#{<<"userId">> => <<"TESTEMAIL">>, <<"tags">> => [<<"HOME">>, <<"WORK">>]}, @@ -176,7 +176,7 @@ user_get_others_vcard(Config) -> user_get_others_vcard(Config, Alice, Bob) -> Client1Fields = [{<<"FN">>, <<"TESTNAME">>}, {<<"EMAIL">>, [{<<"USERID">>, <<"TESTEMAIL">>}, - {<<"HOME">>, []}, {"WORK", []}]}, {<<"EMAIL">>, [{<<"USERID">>, <<"TESTEMAIL2">>}, + {<<"HOME">>, []}, {<<"WORK">>, []}]}, {<<"EMAIL">>, [{<<"USERID">>, <<"TESTEMAIL2">>}, {<<"HOME">>, []}]}], ExpectedResult = #{<<"formattedName">> => <<"TESTNAME">>, <<"email">> => [#{<<"userId">> => <<"TESTEMAIL">>, <<"tags">> => [<<"HOME">>, <<"WORK">>]}, diff --git a/big_tests/tests/inbox_SUITE.erl b/big_tests/tests/inbox_SUITE.erl index b922e0b5e67..782f60ae4e9 100644 --- a/big_tests/tests/inbox_SUITE.erl +++ b/big_tests/tests/inbox_SUITE.erl @@ -1417,7 +1417,7 @@ xmpp_bin_flush(Config) -> %% Bob requests flush through xmpp Iq = escalus_stanza:iq(<<"set">>, [#xmlel{name = <<"empty-bin">>, - attrs = [{<<"xmlns">>, inbox_helper:inbox_ns()}], + attrs = #{<<"xmlns">> => inbox_helper:inbox_ns()}, children = []}]), escalus:send(Bob, Iq), escalus:assert(is_iq_result, [Iq], escalus:wait_for_stanza(Bob)), diff --git a/big_tests/tests/inbox_extensions_SUITE.erl b/big_tests/tests/inbox_extensions_SUITE.erl index 7212d3422b6..2b616ea8962 100644 --- a/big_tests/tests/inbox_extensions_SUITE.erl +++ b/big_tests/tests/inbox_extensions_SUITE.erl @@ -878,7 +878,8 @@ make_inbox_get_properties(To, none) -> Query = escalus_stanza:query_el(inbox_helper:inbox_ns_conversation(), jid_attr(To), []), escalus_stanza:iq(<<"get">>, [Query]); make_inbox_get_properties(To, full_entry) -> - Attrs = [{<<"complete">>, <<"true">>} | jid_attr(To)], + Attrs0 = jid_attr(To), + Attrs = Attrs0#{<<"complete">> => <<"true">>}, Query = escalus_stanza:query_el(inbox_helper:inbox_ns_conversation(), Attrs, []), escalus_stanza:iq(<<"get">>, [Query]). @@ -919,10 +920,10 @@ make_inbox_iq_request(ToClient, Properties) when is_list(Properties) -> -spec make_inbox_iq_request_with_query_id(maybe_client(), proplists:proplist(), map()) -> exml:element(). make_inbox_iq_request_with_query_id(ToClient, Properties, QueryId) -> - JidAttr = jid_attr(ToClient), - IqAttr = id_attr(QueryId), + Attrs0 = jid_attr(ToClient), + Attrs = id_attr(QueryId, Attrs0), Children = props_to_children(Properties), - Query = escalus_stanza:query_el(inbox_helper:inbox_ns_conversation(), JidAttr ++ IqAttr, Children), + Query = escalus_stanza:query_el(inbox_helper:inbox_ns_conversation(), Attrs, Children), inbox_iq(QueryId, Query). inbox_iq(#{iq_id := IqId}, Query) -> @@ -935,11 +936,11 @@ assert_invalid_request(From, Stanza, Value) -> inbox_helper:assert_invalid_form(From, Stanza, Value, Value). -spec jid_attr(maybe_client()) -> proplists:proplist(). -jid_attr(undefined) -> []; -jid_attr(Client) -> [{<<"jid">>, escalus_utils:get_short_jid(Client)}]. +jid_attr(undefined) -> #{}; +jid_attr(Client) -> #{<<"jid">> => escalus_utils:get_short_jid(Client)}. -id_attr(#{queryid := QueryId}) -> [{<<"queryid">>, QueryId}]; -id_attr(_) -> []. +id_attr(#{queryid := QueryId}, Attrs) -> Attrs#{<<"queryid">> => QueryId}; +id_attr(_, Attrs) -> Attrs. props_to_children(L) -> props_to_children(L, []). props_to_children([], Acc) -> Acc; diff --git a/big_tests/tests/inbox_helper.erl b/big_tests/tests/inbox_helper.erl index 130d7f310f3..c572ddd8617 100644 --- a/big_tests/tests/inbox_helper.erl +++ b/big_tests/tests/inbox_helper.erl @@ -374,16 +374,18 @@ make_inbox_stanza() -> -spec make_inbox_stanza(GetParams :: inbox_query_params()) -> exml:element(). make_inbox_stanza(GetParams) -> GetIQ = inbox_iq(GetParams), + Attrs = maybe_query_params(GetParams), QueryTag = #xmlel{name = <<"inbox">>, - attrs = [{<<"xmlns">>, ?NS_ESL_INBOX} | maybe_query_params(GetParams)], + attrs = Attrs#{<<"xmlns">> => ?NS_ESL_INBOX}, children = [make_inbox_form(GetParams) | rsm(GetParams)]}, GetIQ#xmlel{children = [QueryTag]}. -spec make_inbox_stanza(GetParams :: inbox_query_params(), Verify :: boolean()) -> exml:element(). make_inbox_stanza(GetParams, Verify) -> GetIQ = inbox_iq(GetParams), + Attrs = maybe_query_params(GetParams), QueryTag = #xmlel{name = <<"inbox">>, - attrs = [{<<"xmlns">>, ?NS_ESL_INBOX} | maybe_query_params(GetParams)], + attrs = Attrs#{<<"xmlns">> => ?NS_ESL_INBOX}, children = [make_inbox_form(GetParams, Verify) | rsm(GetParams)]}, GetIQ#xmlel{children = [QueryTag]}. @@ -393,12 +395,10 @@ inbox_iq(#{iq_id := IqId}) -> inbox_iq(_) -> escalus_stanza:iq_set(?NS_ESL_INBOX, []). -maybe_query_params(#{queryid := undefined}) -> - []; -maybe_query_params(#{queryid := QueryId}) -> - [{<<"queryid">>, QueryId}]; +maybe_query_params(#{queryid := QueryId}) when QueryId =/= undefined-> + #{<<"queryid">> => QueryId}; maybe_query_params(_) -> - []. + #{}. rsm(Params) -> Max = maps:get(limit, Params, undefined), @@ -420,7 +420,7 @@ rsm(Params) -> case Elems of [] -> []; _ -> [#xmlel{name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = Elems}] end. @@ -445,17 +445,13 @@ make_reset_inbox_stanza(InterlocutorJid) when is_binary(InterlocutorJid) -> escalus_stanza:iq( <<"set">>, [#xmlel{name = <<"reset">>, - attrs = [ - {<<"xmlns">>, inbox_ns_conversation()}, - {<<"jid">>, InterlocutorJid} - ]}]); + attrs = #{<<"xmlns">> => inbox_ns_conversation(), + <<"jid">> => InterlocutorJid}}]); make_reset_inbox_stanza(undefined) -> escalus_stanza:iq( <<"set">>, [#xmlel{name = <<"reset">>, - attrs = [ - {<<"xmlns">>, inbox_ns_conversation()} - ]}]); + attrs = #{<<"xmlns">> => inbox_ns_conversation()}}]); make_reset_inbox_stanza(InterlocutorJid) -> make_reset_inbox_stanza(escalus_utils:get_short_jid(InterlocutorJid)). @@ -601,7 +597,7 @@ stanza_set_affiliations(Room, List) -> aff_to_iq_item({JID, Affiliation}) -> #xmlel{name = <<"item">>, - attrs = [{<<"jid">>, JID}, {<<"affiliation">>, Affiliation}]}. + attrs = #{<<"jid">> => JID, <<"affiliation">> => Affiliation}}. nick(User) -> escalus_utils:get_username(User). @@ -609,7 +605,7 @@ stanza_muc_enter_room(Room, Nick) -> stanza_to_room( escalus_stanza:presence(<<"available">>, [#xmlel{name = <<"x">>, - attrs=[{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}]} + attrs=#{<<"xmlns">> => <<"http://jabber.org/protocol/muc">>}} ]), Room, Nick). diff --git a/big_tests/tests/jingle_SUITE.erl b/big_tests/tests/jingle_SUITE.erl index 6e60f2aa24b..240958367ed 100644 --- a/big_tests/tests/jingle_SUITE.erl +++ b/big_tests/tests/jingle_SUITE.erl @@ -538,13 +538,13 @@ iq_set(I) -> iq_with_id(Stanza). iq_with_id(#xmlel{attrs = Attrs} = Stanza) -> - NewAttrs = lists:keystore(<<"id">>, 1, Attrs, {<<"id">>, uuid:uuid_to_string(uuid:get_v4(), binary_standard)}), + NewAttrs = Attrs#{<<"id">> => uuid:uuid_to_string(uuid:get_v4(), binary_standard)}, Stanza#xmlel{attrs = NewAttrs}. iq_get(I) -> Stanza = #xmlel{name = <<"iq">>, - attrs = [{<<"xmlns">>, <<"jabber:client">>}, - {<<"type">>, <<"get">>}], + attrs = #{<<"xmlns">> => <<"jabber:client">>, + <<"type">> => <<"get">>}, children = [I]}, iq_with_id(Stanza). @@ -554,9 +554,9 @@ jingle_element(Action, Children) -> jingle_element(SID, Action, Children) -> #xmlel{name = <<"jingle">>, - attrs = [{<<"action">>, Action}, - {<<"sid">>, SID}, - {<<"xmlns">>, <<"urn:xmpp:jingle:1">>}], + attrs = #{<<"action">> => Action, + <<"sid">> => SID, + <<"xmlns">> => <<"urn:xmpp:jingle:1">>}, children = Children}. jingle_accept(InviteRequest) -> @@ -591,6 +591,7 @@ jingle_source_update(InviteRequest) -> content_group([Audio, Video])]), iq_set(I). +%% TODO: this seems to be a dead code. remove it if it's not needed anymore jingle_transport_info(InviteRequest, Creator, Media, TransportAttrs) -> SID = exml_query:path(InviteRequest, path_to_jingle_sid()), iq_set(jingle_element(SID, <<"transport-info">>, [trickle_ice_candidate(Creator, Media, TransportAttrs)])). @@ -606,15 +607,16 @@ get_ice_candidates() -> [{<<"foundation">>, <<"1293499931">>}, {<<"component">>, <<"1">>}, {<<"protocol">>, <<"udp">>}, {<<"priority">>, <<"2122260223">>}, {<<"ip">>, <<"172.86.160.16">>}, {<<"port">>, <<"46515">>}, {<<"type">>, <<"host">>}, {<<"generation">>, <<"0">>}, {<<"network">>, <<"1">>}, {<<"id">>, <<"1.1947885zlx">>}] ]. +%% TODO: this seems to be a dead code. remove it if it's not needed anymore trickle_ice_candidate(Creator, Content, TransportAttrs) -> Candidate = #xmlel{name = <<"candidate">>, attrs = TransportAttrs}, Transport = #xmlel{name = <<"transport">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:transports:ice-udp:1">>}, - {<<"ufrag">>, <<"7Gpn">>}, - {<<"pwd">>, <<"MUOzzatqL2qP7n1uRC7msD+c">>}], + attrs = #{<<"xmlns">> => <<"urn:xmpp:jingle:transports:ice-udp:1">>, + <<"ufrag">> => <<"7Gpn">>, + <<"pwd">> => <<"MUOzzatqL2qP7n1uRC7msD+c">>}, children = [Candidate]}, #xmlel{name = <<"content">>, - attrs = [{<<"name">>, Content}, - {<<"creator">>, Creator}], + attrs = #{<<"name">> => Content, + <<"creator">> => Creator}, children = [Transport]}. diff --git a/big_tests/tests/jingle_helper.erl b/big_tests/tests/jingle_helper.erl index 94f9dae2c16..bac1784f125 100644 --- a/big_tests/tests/jingle_helper.erl +++ b/big_tests/tests/jingle_helper.erl @@ -167,10 +167,9 @@ content(video_disabled) -> content_group(ContentEls) -> Contents = [#xmlel{name = <<"content">>, - attrs = [{<<"name">>, exml_query:attr(ContentEl, <<"name">>)}]} + attrs = #{<<"name">> => exml_query:attr(ContentEl, <<"name">>)}} || ContentEl <- ContentEls], #xmlel{name = <<"group">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:apps:grouping:0">>}, - {<<"semantics">>, <<"BUNDLE">>}], + attrs = #{<<"xmlns">> => <<"urn:xmpp:jingle:apps:grouping:0">>, + <<"semantics">> => <<"BUNDLE">>}, children = Contents}. - diff --git a/big_tests/tests/last_SUITE.erl b/big_tests/tests/last_SUITE.erl index fde4ba5f417..84243de7a31 100644 --- a/big_tests/tests/last_SUITE.erl +++ b/big_tests/tests/last_SUITE.erl @@ -268,10 +268,11 @@ answer_last_activity(IQ = #xmlel{name = <<"iq">>}) -> To = exml_query:attr(IQ, <<"to">>), Id = exml_query:attr(IQ, <<"id">>), #xmlel{name = <<"iq">>, - attrs = [{<<"from">>, To}, {<<"to">>, From}, {<<"id">>, Id}, {<<"type">>, <<"result">>}], + attrs = #{<<"from">> => To, <<"to">> => From, <<"id">> => Id, + <<"type">> => <<"result">>}, children = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_LAST_ACTIVITY}, - {<<"seconds">>, <<"0">>}]} + attrs = #{<<"xmlns">> => ?NS_LAST_ACTIVITY, + <<"seconds">> => <<"0">>}} ]}. required_modules() -> diff --git a/big_tests/tests/local_iq_SUITE.erl b/big_tests/tests/local_iq_SUITE.erl index 5bb6f1b4427..f59b4947bb6 100644 --- a/big_tests/tests/local_iq_SUITE.erl +++ b/big_tests/tests/local_iq_SUITE.erl @@ -87,10 +87,10 @@ route_iq(Alice, Timeout) -> To = jid:from_binary(Jid), From = jid:from_binary(Server), Query = #xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, <<"cooltestns">>}]}, + attrs = #{<<"xmlns">> => <<"cooltestns">>}}, Xml = #xmlel{name = <<"iq">>, - attrs = [{<<"type">>, <<"get">>}, - {<<"from">>, Server}, {<<"to">>, Jid}], + attrs = #{<<"type">> => <<"get">>, + <<"from">> => Server, <<"to">> => Jid}, children = [Query]}, Acc = rpc(mim(), mongoose_acc, new, [#{location => #{}, lserver => Server, element => Xml}]), diff --git a/big_tests/tests/login_SUITE.erl b/big_tests/tests/login_SUITE.erl index 2bb61bee1b9..319e614e263 100644 --- a/big_tests/tests/login_SUITE.erl +++ b/big_tests/tests/login_SUITE.erl @@ -548,11 +548,11 @@ restore_c2s(Config) -> -define(NS_SASL, <<"urn:ietf:params:xml:ns:xmpp-sasl">>). auth_stanza(Mech, Payload) -> #xmlel{name = <<"auth">>, - attrs = [{<<"xmlns">>, ?NS_SASL}, - {<<"mechanism">>, Mech}], + attrs = #{<<"xmlns">> => ?NS_SASL, + <<"mechanism">> => Mech}, children = [#xmlcdata{content = base64:encode(Payload)}]}. auth_response(Payload) -> #xmlel{name = <<"response">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], + attrs = #{<<"xmlns">> => ?NS_SASL}, children = [#xmlcdata{content = base64:encode(Payload)}]}. diff --git a/big_tests/tests/mam_SUITE.erl b/big_tests/tests/mam_SUITE.erl index 1e940df432d..0ca29134804 100644 --- a/big_tests/tests/mam_SUITE.erl +++ b/big_tests/tests/mam_SUITE.erl @@ -2669,13 +2669,13 @@ muc_sanitize_x_user_in_non_anon_rooms(Config) -> escalus:wait_for_stanzas(Alice, 1), X = #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, <<"http://jabber.org/protocol/muc#user">>}], + attrs = #{<<"xmlns">> => <<"http://jabber.org/protocol/muc#user">>}, children = [#xmlel{name = <<"item">>, - attrs = [{<<"affiliation">>, <<"owner">>}, - {<<"jid">>, SpoofJid}, - {<<"role">>, <<"moderator">>}]}]}, + attrs = #{<<"affiliation">> => <<"owner">>, + <<"jid">> => SpoofJid, + <<"role">> => <<"moderator">>}}]}, Body = #xmlel{name = <<"body">>, children = [#xmlcdata{content = Text}]}, - Stanza = #xmlel{name = <<"message">>, attrs = [{<<"type">>, <<"groupchat">>}], + Stanza = #xmlel{name = <<"message">>, attrs = #{<<"type">> => <<"groupchat">>}, children = [Body, X]}, %% Bob sends to the chat room. @@ -3605,7 +3605,7 @@ prefs_set_cdata_request(Config) -> %% escalus:send(Alice, stanza_prefs_set_request(<<"roster">>, [<<"romeo@montague.net">>, - {xmlcdata, <<"\n">>}, %% Put as it is + #xmlcdata{content = <<"\n">>}, %% Put as it is <<"montague@montague.net">>], [], mam_ns_binary_v04())), ReplySet = escalus:wait_for_stanza(Alice), @@ -3713,7 +3713,7 @@ muc_prefs_set_cdata_request(ConfigIn) -> Room = ?config(room, Config), escalus:send(Alice, stanza_to_room(stanza_prefs_set_request(<<"roster">>, [<<"romeo@montague.net">>, - {xmlcdata, <<"\n">>}, %% Put as it is + #xmlcdata{content = <<"\n">>}, %% Put as it is <<"montague@montague.net">>], [], mam_ns_binary_v04()), Room)), ReplySet = escalus:wait_for_stanza(Alice), @@ -4138,14 +4138,14 @@ expect_only_original_message(Client, Body) -> retraction_message(Type, To, ApplyToElement) -> #xmlel{name = <<"message">>, - attrs = [{<<"type">>, Type}, - {<<"to">>, To}], + attrs = #{<<"type">> => Type, + <<"to">> => To}, children = [ApplyToElement]}. origin_id_element(OriginId) -> #xmlel{name = <<"origin-id">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:sid:0">>}, - {<<"id">>, OriginId}]}. + attrs = #{<<"xmlns">> => <<"urn:xmpp:sid:0">>, + <<"id">> => OriginId}}. apply_to_element(Config, Copy) -> {RetractOn, Id} = case ?config(retract_on, Config) of @@ -4153,15 +4153,16 @@ apply_to_element(Config, Copy) -> stanza_id -> {stanza_id, stanza_id_from_msg(Copy)}; none -> {origin_id, none} end, + Attrs = #{<<"xmlns">> => <<"urn:xmpp:fasten:0">>}, #xmlel{name = <<"apply-to">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:fasten:0">>} | maybe_append_id(Id)], + attrs = maybe_append_id(Id, Attrs), children = [retract_element(RetractOn)] }. -maybe_append_id(none) -> - []; -maybe_append_id(Id) -> - [{<<"id">>, Id}]. +maybe_append_id(none, Attrs) -> + Attrs; +maybe_append_id(Id, Attrs) -> + Attrs#{<<"id">> => Id}. stanza_id_from_msg(Msg) -> case exml_query:path(Msg, [{element, <<"stanza-id">>}, {attr, <<"id">>}]) of @@ -4171,10 +4172,10 @@ stanza_id_from_msg(Msg) -> retract_element(origin_id) -> #xmlel{name = <<"retract">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:message-retract:0">>}]}; + attrs = #{<<"xmlns">> => <<"urn:xmpp:message-retract:0">>}}; retract_element(stanza_id) -> #xmlel{name = <<"retract">>, - attrs = [{<<"xmlns">>, <<"urn:esl:message-retract-by-stanza-id:0">>}]}. + attrs = #{<<"xmlns">> => <<"urn:esl:message-retract-by-stanza-id:0">>}}. origin_id() -> <<"orig-id-1">>. @@ -4199,7 +4200,7 @@ assert_failed_to_decode_message(ArcMsg) -> #forwarded_message{message_children = [Msg]} = Forwarded, ?assertMatch(#xmlel{ name = <<"error">>, - attrs = [{<<"code">>, <<"500">>}, {<<"type">>,<<"wait">>}], + attrs = #{<<"code">> := <<"500">>, <<"type">> := <<"wait">>}, children = [#xmlel{name = <<"internal-server-error">>}, #xmlel{name = <<"text">>, children = [#xmlcdata{content = Err}]}]}, Msg). diff --git a/big_tests/tests/mam_helper.erl b/big_tests/tests/mam_helper.erl index 58cf2fcc13b..489c68aea4c 100644 --- a/big_tests/tests/mam_helper.erl +++ b/big_tests/tests/mam_helper.erl @@ -183,13 +183,16 @@ stanzas_ns() -> <<"urn:ietf:params:xml:ns:xmpp-stanzas">>. skip_undefined(Xs) -> [X || X <- Xs, X =/= undefined]. -maybe_attr(_, undefined) -> - []; maybe_attr(K, V) -> - [{K, V}]. + maybe_attr(K, V, #{}). + +maybe_attr(_, undefined, Attrs) -> + Attrs; +maybe_attr(K, V, Attrs) -> + Attrs#{K => V}. mam_ns_attr(P) -> - [{<<"xmlns">>, get_prop(mam_ns, P)}]. + #{<<"xmlns">> => get_prop(mam_ns, P)}. maybe_with_elem(undefined) -> undefined; @@ -201,7 +204,7 @@ maybe_with_elem(BWithJID) -> stanza_metadata_request() -> escalus_stanza:iq(<<"get">>, [#xmlel{name = <<"metadata">>, - attrs = [{<<"xmlns">>, mam_ns_binary_v06()}]}]). + attrs = #{<<"xmlns">> => mam_ns_binary_v06()}}]). %% An optional 'queryid' attribute allows the client to match results to %% a certain query. @@ -285,10 +288,10 @@ stanza_lookup_messages_iq(P, Params) -> IncludeGroupChat = maps:get(include_group_chat, Params, undefined), MessagesIDs = maps:get(messages_ids, Params, undefined), + Attrs = mam_ns_attr(P), escalus_stanza:iq(<<"set">>, [#xmlel{ name = <<"query">>, - attrs = mam_ns_attr(P) - ++ maybe_attr(<<"queryid">>, QueryId), + attrs = maybe_attr(<<"queryid">>, QueryId, Attrs), children = skip_undefined([ form_x(BStart, BEnd, BWithJID, RSM, TextSearch, IncludeGroupChat, MessagesIDs), maybe_rsm_elem(RSM), @@ -335,10 +338,10 @@ form_bool_field(_Name, _) -> undefined. stanza_retrieve_form_fields(QueryId, NS) -> + Attrs = #{<<"xmlns">> => NS}, escalus_stanza:iq(<<"get">>, [#xmlel{ name = <<"query">>, - attrs = [{<<"xmlns">>, NS}] - ++ maybe_attr(<<"queryid">>, QueryId), + attrs = maybe_attr(<<"queryid">>, QueryId, Attrs), children = [] }]). @@ -432,31 +435,31 @@ stanza_prefs_set_request(DefaultMode, AlwaysJIDs, NeverJIDs, Namespace) -> children = encode_jids(AlwaysJIDs)}, NeverEl = #xmlel{name = <<"never">>, children = encode_jids(NeverJIDs)}, + Attrs = #{<<"xmlns">> => Namespace}, escalus_stanza:iq(<<"set">>, [#xmlel{ name = <<"prefs">>, - attrs = [{<<"xmlns">>, Namespace}] - ++ [{<<"default">>, DefaultMode} || is_def(DefaultMode)], + attrs = maybe_attr(<<"default">>, DefaultMode, Attrs), children = [AlwaysEl, NeverEl] }]). stanza_prefs_get_request(Namespace) -> escalus_stanza:iq(<<"get">>, [#xmlel{ name = <<"prefs">>, - attrs = [{<<"xmlns">>, Namespace}] + attrs = #{<<"xmlns">> => Namespace} }]). stanza_query_get_request(Namespace) -> escalus_stanza:iq(<<"get">>, [#xmlel{ name = <<"query">>, - attrs = [{<<"xmlns">>, Namespace}] + attrs = #{<<"xmlns">> => Namespace} }]). %% Allows to cdata to be put as it is encode_jids(JIDs) -> [encode_jid_or_cdata(JID) || JID <- JIDs]. -encode_jid_or_cdata({xmlcdata, Text}) -> - {xmlcdata, Text}; +encode_jid_or_cdata(#xmlcdata{content = Text}) -> + #xmlcdata{content = Text}; encode_jid_or_cdata(JID) -> #xmlel{name = <<"jid">>, children = [#xmlcdata{content = JID}]}. @@ -467,8 +470,8 @@ encode_jid_or_cdata(JID) -> parse_forwarded_message(#xmlel{name = <<"message">>, attrs = Attrs, children = Children}) -> M = #forwarded_message{ - from = proplists:get_value(<<"from">>, Attrs), - to = proplists:get_value(<<"to">>, Attrs), + from = get_attr(<<"from">>, Attrs), + to = get_attr(<<"to">>, Attrs), has_x_user_element = false}, lists:foldl(fun parse_children_message/2, M, Children). @@ -476,8 +479,8 @@ parse_children_message(#xmlel{name = <<"result">>, attrs = Attrs, children = Children}, M) -> M1 = M#forwarded_message{ - result_queryid = proplists:get_value(<<"queryid">>, Attrs), - result_id = proplists:get_value(<<"id">>, Attrs)}, + result_queryid = get_attr(<<"queryid">>, Attrs), + result_id = get_attr(<<"id">>, Attrs)}, lists:foldl(fun parse_children_message_result/2, M1, Children). parse_children_message_result(#xmlel{name = <<"forwarded">>, @@ -488,24 +491,24 @@ parse_children_message_result(#xmlel{name = <<"forwarded">>, parse_children_message_result_forwarded(#xmlel{name = <<"delay">>, attrs = Attrs}, M) -> M#forwarded_message{ - delay_from = proplists:get_value(<<"from">>, Attrs), - delay_stamp = proplists:get_value(<<"stamp">>, Attrs)}; + delay_from = get_attr(<<"from">>, Attrs), + delay_stamp = get_attr(<<"stamp">>, Attrs)}; parse_children_message_result_forwarded(#xmlel{name = <<"message">>, attrs = Attrs, children = Children}, M) -> M1 = M#forwarded_message{ - message_to = proplists:get_value(<<"to">>, Attrs), - message_from = proplists:get_value(<<"from">>, Attrs), - message_type = proplists:get_value(<<"type">>, Attrs)}, + message_to = get_attr(<<"to">>, Attrs), + message_from = get_attr(<<"from">>, Attrs), + message_type = get_attr(<<"type">>, Attrs)}, lists:foldl(fun parse_children_message_result_forwarded_message/2, M1, Children). parse_children_message_result_forwarded_message(#xmlel{name = <<"body">>, - children = [{xmlcdata, Body}]}, M) -> + children = [#xmlcdata{content = Body}]}, M) -> M#forwarded_message{message_body = Body}; parse_children_message_result_forwarded_message(#xmlel{name = <<"x">>, attrs = Attrs} = XEl, M) -> - IsUser = lists:member({<<"xmlns">>, <<"http://jabber.org/protocol/muc#user">>}, Attrs), + IsUser = get_attr(<<"xmlns">>, Attrs) =:= <<"http://jabber.org/protocol/muc#user">>, M#forwarded_message{has_x_user_element = IsUser, message_xs = [XEl | M#forwarded_message.message_xs]}; %% Parse `' or chat markers. @@ -583,8 +586,8 @@ parse_set_and_iq(IQ, Set, QueryId, Complete) -> count = maybe_binary_to_integer(exml_query:path(Set, [{element, <<"count">>}, cdata]))}. -is_def(X) -> X =/= undefined. - +get_attr(Key, Attrs) -> + maps:get(Key, Attrs, undefined). parse_prefs_result_iq(#xmlel{name = <<"iq">>, children = Children}) -> IQ = #prefs_result_iq{}, @@ -593,7 +596,7 @@ parse_prefs_result_iq(#xmlel{name = <<"iq">>, children = Children}) -> parse_children_prefs_iq(#xmlel{name = <<"prefs">>, attrs = Attrs, children = Children}, IQ) -> - DefaultMode = proplists:get_value(<<"default">>, Attrs), + DefaultMode = get_attr(<<"default">>, Attrs), IQ1 = IQ#prefs_result_iq{default_mode = DefaultMode}, lists:foldl(fun parse_children_prefs_iq_prefs/2, IQ1, Children). @@ -610,7 +613,7 @@ parse_children_prefs_iq_prefs(#xmlel{name = <<"never">>, parse_jids(Els) -> [escalus_utils:jid_to_lower(JID) %% MongooseIM normalizes JIDs - || #xmlel{name = <<"jid">>, children = [{xmlcdata, JID}]} <- Els]. + || #xmlel{name = <<"jid">>, children = [#xmlcdata{content = JID}]} <- Els]. %%-------------------------------------------------------------------- %% Helpers (muc) @@ -1387,9 +1390,9 @@ add_nostore_hint(#xmlel{children=Children}=Elem) -> Elem#xmlel{children=Children ++ [hint_elem(no_store)]}. hint_elem(store) -> - #xmlel{name = <<"store">>, attrs = [{<<"xmlns">>, <<"urn:xmpp:hints">>}]}; + #xmlel{name = <<"store">>, attrs = #{<<"xmlns">> => <<"urn:xmpp:hints">>}}; hint_elem(no_store) -> - #xmlel{name = <<"no-store">>, attrs = [{<<"xmlns">>, <<"urn:xmpp:hints">>}]}. + #xmlel{name = <<"no-store">>, attrs = #{<<"xmlns">> => <<"urn:xmpp:hints">>}}. has_x_user_element(ArcMsg) -> ParsedMess = parse_forwarded_message(ArcMsg), diff --git a/big_tests/tests/mam_send_message_SUITE_data/mam_send_message_example.erl b/big_tests/tests/mam_send_message_SUITE_data/mam_send_message_example.erl index e2995c09def..c4abdbf2613 100644 --- a/big_tests/tests/mam_send_message_SUITE_data/mam_send_message_example.erl +++ b/big_tests/tests/mam_send_message_SUITE_data/mam_send_message_example.erl @@ -49,4 +49,4 @@ send_message(Row, From, To, Mess) -> mod_mam_utils:send_message(Row, From, To, Mess2). new_subelem(#{some_hash := SomeHash}) -> - #xmlel{name = <<"some_hash">>, attrs = [{<<"value">>, integer_to_binary(SomeHash)}]}. + #xmlel{name = <<"some_hash">>, attrs = #{<<"value">> => integer_to_binary(SomeHash)}}. diff --git a/big_tests/tests/mim_c2s_SUITE.erl b/big_tests/tests/mim_c2s_SUITE.erl index 985c1ff89f0..b3dff4de3f1 100644 --- a/big_tests/tests/mim_c2s_SUITE.erl +++ b/big_tests/tests/mim_c2s_SUITE.erl @@ -94,7 +94,7 @@ client_sets_stream_from_server_answers_with_to(Config) -> [StreamStartAnswer, _StreamFeatures] = escalus_client:wait_for_stanzas(Alice, 2, 500), #xmlstreamstart{name = <<"stream:stream">>, attrs = Attrs} = StreamStartAnswer, FromClient = jid:from_binary(escalus_utils:get_jid(Alice)), - {_, FromServerBin} = lists:keyfind(<<"to">>, 1, Attrs), + FromServerBin = maps:get(<<"to">>, Attrs), FromServer = jid:from_binary(FromServerBin), ?assert(jid:are_equal(FromClient, FromServer)), escalus_connection:stop(Alice). @@ -141,7 +141,7 @@ too_big_stanza_is_rejected(Config) -> too_big_opening_tag_is_rejected(Config) -> AliceSpec = escalus_fresh:create_fresh_user(Config, alice), {ok, Alice, _Features} = escalus_connection:start(AliceSpec, []), - BigAttrs = [{<<"bigattr">>, binary:encode_hex(crypto:strong_rand_bytes(?MAX_STANZA_SIZE))}], + BigAttrs = #{<<"bigattr">> => binary:encode_hex(crypto:strong_rand_bytes(?MAX_STANZA_SIZE))}, escalus_client:send(Alice, #xmlel{name = <<"stream:stream">>, attrs = BigAttrs}), escalus:assert(is_stream_start, escalus_client:wait_for_stanza(Alice)), escalus:assert(is_stream_error, [<<"xml-not-well-formed">>, <<>>], @@ -202,12 +202,12 @@ stream_start(Client) -> stream_start(Server, From) -> #xmlstreamstart{name = <<"stream:stream">>, - attrs = [{<<"to">>, Server}, - {<<"from">>, From}, - {<<"version">>, <<"1.0">>}, - {<<"xml:lang">>, <<"en">>}, - {<<"xmlns">>, <<"jabber:client">>}, - {<<"xmlns:stream">>, <<"http://etherx.jabber.org/streams">>}]}. + attrs = #{<<"to">> => Server, + <<"from">> => From, + <<"version">> => <<"1.0">>, + <<"xml:lang">> => <<"en">>, + <<"xmlns">> => <<"jabber:client">>, + <<"xmlns:stream">> => <<"http://etherx.jabber.org/streams">>}}. save_c2s_listener(Config) -> C2SPort = ct:get_config({hosts, mim, c2s_port}), diff --git a/big_tests/tests/mod_blocking_SUITE.erl b/big_tests/tests/mod_blocking_SUITE.erl index 0cde498231e..0e1439be5a3 100644 --- a/big_tests/tests/mod_blocking_SUITE.erl +++ b/big_tests/tests/mod_blocking_SUITE.erl @@ -470,74 +470,62 @@ get_blocklist(User) -> get_blocklist_stanza() -> Payload = #xmlel{name = <<"blocklist">>, - attrs=[{<<"xmlns">>, ?NS_BLOCKING}]}, + attrs=#{<<"xmlns">> => ?NS_BLOCKING}}, #xmlel{name = <<"iq">>, - attrs = [{<<"type">>, <<"get">>}], - children = [Payload]}. + attrs = #{<<"type">> => <<"get">>}, + children = [Payload]}. block_users_stanza(UsersToBlock) -> Childs = [item_el(U) || U <- UsersToBlock], Payload = #xmlel{name = <<"block">>, - attrs=[{<<"xmlns">>, ?NS_BLOCKING}], - children = Childs - }, - #xmlel{name = <<"iq">>, - attrs = [{<<"type">>, <<"set">>}], - children = [Payload]}. + attrs=#{<<"xmlns">> => ?NS_BLOCKING}, + children = Childs}, + set_iq(Payload). block_users_stanza_with_white_spaces(UsersToBlock) -> Childs = [item_el(U) || U <- UsersToBlock], % when client adds some white characters in blocking list - WhiteSpacedChilds = Childs ++ [{xmlcdata, "\n"}], + WhiteSpacedChilds = Childs ++ [#xmlcdata{content = "\n"}], Payload = #xmlel{name = <<"block">>, - attrs=[{<<"xmlns">>, ?NS_BLOCKING}], - children = WhiteSpacedChilds - }, - #xmlel{name = <<"iq">>, - attrs = [{<<"type">>, <<"set">>}], - children = [Payload]}. + attrs=#{<<"xmlns">> => ?NS_BLOCKING}, + children = WhiteSpacedChilds}, + set_iq(Payload). -%%block_user_stanza(UserToBlock) -> -%% Payload = #xmlel{name = <<"block">>, -%% attrs=[{<<"xmlns">>, ?NS_BLOCKING}], -%% children = [item_el(UserToBlock)] -%% }, -%% #xmlel{name = <<"iq">>, -%% attrs = [{<<"type">>, <<"set">>}], -%% children = Payload}. +block_user_stanza(UserToBlock) -> + Payload = #xmlel{name = <<"block">>, + attrs=#{<<"xmlns">> => ?NS_BLOCKING}, + children = [item_el(UserToBlock)]}, + set_iq(Payload). unblock_user_stanza(UserToUnblock) -> Payload = #xmlel{name = <<"unblock">>, - attrs=[{<<"xmlns">>, ?NS_BLOCKING}], - children = [item_el(UserToUnblock)] - }, - #xmlel{name = <<"iq">>, - attrs = [{<<"type">>, <<"set">>}], - children = [Payload]}. + attrs=#{<<"xmlns">> => ?NS_BLOCKING}, + children = [item_el(UserToUnblock)]}, + set_iq(Payload). unblock_users_stanza(UsersToBlock) -> Childs = [item_el(U) || U <- UsersToBlock], Payload = #xmlel{name = <<"unblock">>, - attrs=[{<<"xmlns">>, ?NS_BLOCKING}], - children = Childs - }, - #xmlel{name = <<"iq">>, - attrs = [{<<"type">>, <<"set">>}], - children = [Payload]}. + attrs=#{<<"xmlns">> => ?NS_BLOCKING}, + children = Childs}, + set_iq(Payload). unblock_all_stanza() -> Payload = #xmlel{name = <<"unblock">>, - attrs=[{<<"xmlns">>, ?NS_BLOCKING}], + attrs= #{<<"xmlns">> => ?NS_BLOCKING}, children = [] }, + set_iq(Payload). + +set_iq(Payload) -> #xmlel{name = <<"iq">>, - attrs = [{<<"type">>, <<"set">>}], - children = [Payload]}. + attrs = #{<<"type">> => <<"set">>}, + children = [Payload]}. item_el(User) when is_binary(User) -> #xmlel{name = <<"item">>, - attrs = [{<<"jid">>, User}]}. + attrs = #{<<"jid">> => User}}. %% %% predicates %% @@ -555,42 +543,40 @@ is_xep191_not_available(#xmlel{} = Stanza) -> {attr, <<"xmlns">>}]). -is_blocklist_result_empty(#xmlel{children = [#xmlel{name =Name, - attrs = Attrs, - children= Child}]} = Stanza) -> +is_blocklist_result_empty(#xmlel{children = [Child]} = Stanza) -> true = escalus_pred:is_iq(Stanza), - <<"blocklist">> = Name, - {<<"xmlns">>, ?NS_BLOCKING} = lists:keyfind(<<"xmlns">>, 1, Attrs), - [] = Child, + #xmlel{name = <<"blocklist">>, + attrs = #{<<"xmlns">> := ?NS_BLOCKING}, + children = []} = Child, true. blocklist_result_has(ExpectedUser, Stanza) -> true = escalus_pred:is_iq(Stanza), Blocklist = hd(Stanza#xmlel.children), - Attrs = Blocklist#xmlel.attrs, + #{<<"xmlns">> := ?NS_BLOCKING} = Blocklist#xmlel.attrs, Children = Blocklist#xmlel.children, <<"blocklist">> = Blocklist#xmlel.name, - {<<"xmlns">>, ?NS_BLOCKING} = lists:keyfind(<<"xmlns">>, 1, Attrs), true == lists:member(ExpectedUser, get_blocklist_items(Children)). is_xep191_push(Type, #xmlel{attrs = A, children = [#xmlel{name = Type, - attrs = Attrs}]}=Stanza) -> + attrs = Attrs}]}=Stanza) -> true = escalus_pred:is_iq_set(Stanza), - {<<"id">>, <<"push">>} = lists:keyfind(<<"id">>, 1, A), - {<<"xmlns">>, ?NS_BLOCKING} = lists:keyfind(<<"xmlns">>, 1, Attrs), + #{<<"xmlns">> := ?NS_BLOCKING} = Attrs, + #{<<"id">> := <<"push">>} = A, true. is_xep191_push(Type, [], #xmlel{children = [#xmlel{name = Type, children = []}]}=Stanza) -> is_xep191_push(Type, Stanza); is_xep191_push(Type, [], #xmlel{children = [#xmlel{name = Type, children = _}]}) -> false; -is_xep191_push(Type, JIDs, #xmlel{attrs = _, children = [#xmlel{name = Type, - attrs = Attrs, children = Items}]}=Stanza) -> +is_xep191_push(Type, JIDs, #xmlel{children = [#xmlel{name = Type, + attrs = Attrs, + children = Items}]}=Stanza) -> true = escalus_pred:is_iq_set(Stanza), - {<<"xmlns">>, ?NS_BLOCKING} = lists:keyfind(<<"xmlns">>, 1, Attrs), + #{<<"xmlns">> := ?NS_BLOCKING} = Attrs, F = fun(El) -> - #xmlel{name = <<"item">>, attrs = [{<<"jid">>, Value}]} = El, - lists:member(Value, JIDs) + #xmlel{name = <<"item">>, attrs = #{<<"jid">> := Value}} = El, + lists:member(Value, JIDs) end, TrueList = lists:map(F, Items), lists:all(fun(El) -> El end, TrueList); @@ -605,8 +591,7 @@ bare(C) -> escalus_utils:jid_to_lower(escalus_client:short_jid(C)). get_blocklist_items(Items) -> lists:map(fun(#xmlel{name = <<"item">>, attrs=A}) -> - {_, R} = lists:keyfind(<<"jid">>, 1, A), - R + maps:get(<<"jid">>, A) end, Items). user_blocks(Blocker, Blockees) when is_list(Blockees) -> diff --git a/big_tests/tests/mod_event_pusher_sns_SUITE.erl b/big_tests/tests/mod_event_pusher_sns_SUITE.erl index e3ab7be7d4e..a1344ad0124 100644 --- a/big_tests/tests/mod_event_pusher_sns_SUITE.erl +++ b/big_tests/tests/mod_event_pusher_sns_SUITE.erl @@ -290,7 +290,7 @@ stanza_muc_enter_room(Room, Nick) -> stanza_to_room( escalus_stanza:presence(<<"available">>, [#xmlel{name = <<"x">>, - attrs=[{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}]} + attrs=#{<<"xmlns">> => <<"http://jabber.org/protocol/muc">>}} ]), Room, Nick). diff --git a/big_tests/tests/mod_http_upload_SUITE.erl b/big_tests/tests/mod_http_upload_SUITE.erl index beb006654d2..e6d8cac114d 100644 --- a/big_tests/tests/mod_http_upload_SUITE.erl +++ b/big_tests/tests/mod_http_upload_SUITE.erl @@ -395,19 +395,18 @@ create_slot_request_stanza(Server, Filename, Size, ContentType) when is_integer( create_slot_request_stanza(Server, Filename, integer_to_binary(Size), ContentType); create_slot_request_stanza(Server, Filename, BinSize, ContentType) -> #xmlel{name = <<"iq">>, - attrs = [{<<"type">>, <<"get">>}, {<<"to">>, Server}], + attrs = #{<<"type">> => <<"get">>, <<"to">> => Server}, children = [create_request_element(Filename, BinSize, ContentType)]}. create_request_element(Filename, BinSize, ContentType) -> - ContentTypeEl = case ContentType of - undefined -> []; - _ -> [{<<"content-type">>, ContentType}] + ContentTypeAttr = case ContentType of + undefined -> #{}; + _ -> #{<<"content-type">> => ContentType} end, #xmlel{name = <<"request">>, - attrs = [{<<"xmlns">>, ?NS_HTTP_UPLOAD_030}, - {<<"filename">>, Filename}, - {<<"size">>, BinSize} - | ContentTypeEl]}. + attrs = ContentTypeAttr#{<<"xmlns">> => ?NS_HTTP_UPLOAD_030, + <<"filename">> => Filename, + <<"size">> => BinSize}}. has_upload_namespace(#xmlel{name = <<"iq">>, children = [#xmlel{ name = <<"slot">> } = Slot]}) -> ?NS_HTTP_UPLOAD_030 == exml_query:attr(Slot, <<"xmlns">>); diff --git a/big_tests/tests/mod_ping_SUITE.erl b/big_tests/tests/mod_ping_SUITE.erl index 04bdae20451..7cd2dda24d2 100644 --- a/big_tests/tests/mod_ping_SUITE.erl +++ b/big_tests/tests/mod_ping_SUITE.erl @@ -172,7 +172,7 @@ wrong_ping(Config) -> fun(Alice) -> Domain = domain(), IQ = escalus_stanza:iq(<<"get">>, [#xmlel{name = <<"unsupported">>, - attrs = [{<<"xmlns">>, ?NS_PING}] + attrs = #{<<"xmlns">> => ?NS_PING} }]), PingReq = escalus_stanza:to(IQ, Domain), escalus_client:send(Alice, PingReq), @@ -187,10 +187,10 @@ service_unavailable_response(Config) -> PingReq = wait_for_ping_req(Alice), PingId = exml_query:attr(PingReq, <<"id">>), - ErrorStanzaBody = [#xmlel{name = <<"ping">>, attrs = [{<<"xmlns">>, ?NS_PING}]}, - #xmlel{name = <<"error">>, attrs = [{<<"type">>, <<"cancel">>}], + ErrorStanzaBody = [#xmlel{name = <<"ping">>, attrs = #{<<"xmlns">> => ?NS_PING}}, + #xmlel{name = <<"error">>, attrs = #{<<"type">> => <<"cancel">>}, children = [#xmlel{name = <<"service-unavailable">>, - attrs = [{<<"xmlns">>, ?NS_STANZA_ERRORS}]}]}], + attrs = #{<<"xmlns">> => ?NS_STANZA_ERRORS}}]}], ErrorStanza = escalus_stanza:set_id( escalus_stanza:iq(domain(), <<"error">>, ErrorStanzaBody), PingId), escalus_client:send(Alice, ErrorStanza), diff --git a/big_tests/tests/mod_time_SUITE.erl b/big_tests/tests/mod_time_SUITE.erl index 90ec4e81d36..47d5b0bbee2 100644 --- a/big_tests/tests/mod_time_SUITE.erl +++ b/big_tests/tests/mod_time_SUITE.erl @@ -97,26 +97,26 @@ time_service_discovery(Config) -> time_request_stanza(Server, ID) -> #xmlel{name = <<"iq">>, - attrs = [{<<"type">>, <<"get">>}, - {<<"id">>, ID}, {<<"to">>, Server}], + attrs = #{<<"type">> => <<"get">>, + <<"id">> => ID, + <<"to">> => Server}, children = [#xmlel{name = <<"time">>, - attrs = [{<<"xmlns">>, ?NS_TIME}]}]}. + attrs = #{<<"xmlns">> => ?NS_TIME}}]}. -check_ns(#xmlel{name = <<"iq">>, attrs = _, children = [Child]}) -> +check_ns(#xmlel{name = <<"iq">>, children = [Child]}) -> case Child of - #xmlel{name = <<"time">>, attrs = [{<<"xmlns">>, ?NS_TIME}], children = _} -> true; + #xmlel{name = <<"time">>, attrs = #{<<"xmlns">> := ?NS_TIME}, children = _} -> true; _ -> false end; - check_ns(_) -> false. -time_from_stanza(#xmlel{name = <<"iq">>, attrs = _, children = [Child]}) -> +time_from_stanza(#xmlel{name = <<"iq">>, children = [Child]}) -> case Child of - #xmlel{name = <<"time">>, attrs = [{<<"xmlns">>, ?NS_TIME}], children = Times} -> + #xmlel{name = <<"time">>, attrs = #{<<"xmlns">> := ?NS_TIME}, children = Times} -> case Times of - [#xmlel{name = <<"tzo">>, attrs = _, children = [#xmlcdata{content = Tzo}]}, - #xmlel{name = <<"utc">>, attrs = _, children = [#xmlcdata{content = Utc}]}] -> + [#xmlel{name = <<"tzo">>, children = [#xmlcdata{content = Tzo}]}, + #xmlel{name = <<"utc">>, children = [#xmlcdata{content = Utc}]}] -> {Tzo, Utc}; _ -> no_timezone end; diff --git a/big_tests/tests/mod_version_SUITE.erl b/big_tests/tests/mod_version_SUITE.erl index f41f629ab84..8bb379e62f9 100644 --- a/big_tests/tests/mod_version_SUITE.erl +++ b/big_tests/tests/mod_version_SUITE.erl @@ -7,6 +7,8 @@ -include_lib("exml/include/exml.hrl"). -import(config_parser_helper, [default_mod_config/1, mod_config/2]). + +-define(IS_EMPTY(X), (X =:= #{})). %%-------------------------------------------------------------------- %% Suite configuration %%-------------------------------------------------------------------- @@ -102,16 +104,16 @@ ask_for_version_with_os(Config) -> soft_version_stanza(Server, ID) -> #xmlel{name = <<"iq">>, - attrs = [{<<"type">>, <<"get">>}, - {<<"to">>, Server}, - {<<"id">>, ID}], + attrs = #{<<"type">> => <<"get">>, + <<"to">> => Server, + <<"id">> => ID}, children = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_SOFT_VERSION}]}]}. + attrs = #{<<"xmlns">> => ?NS_SOFT_VERSION}}]}. -check_namespace(#xmlel{name = <<"iq">>, attrs = _, children = [Child]}) -> +check_namespace(#xmlel{name = <<"iq">>, children = [Child]}) -> case Child of #xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_SOFT_VERSION}], + attrs = #{<<"xmlns">> := ?NS_SOFT_VERSION}, children = _} -> true; _ -> @@ -120,14 +122,19 @@ check_namespace(#xmlel{name = <<"iq">>, attrs = _, children = [Child]}) -> check_namespace(_) -> false. -check_name_and_version_presence(#xmlel{name = <<"iq">>, attrs = _, children = [Child]}) -> +check_name_and_version_presence(#xmlel{name = <<"iq">>, children = [Child]}) -> case Child of #xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_SOFT_VERSION}], + attrs = #{<<"xmlns">> := ?NS_SOFT_VERSION}, children = Children} -> case Children of - [#xmlel{name = <<"name">>, attrs = [], children = [#xmlcdata{content = _}]}, - #xmlel{name = <<"version">>, attrs = [], children = [#xmlcdata{content = _}]}] -> + [#xmlel{name = <<"name">>, + attrs = A1, + children = [#xmlcdata{content = _}]}, + #xmlel{name = <<"version">>, + attrs = A2, + children = [#xmlcdata{content = _}]}] when ?IS_EMPTY(A1), + ?IS_EMPTY(A2) -> true; _ -> false @@ -138,15 +145,20 @@ check_name_and_version_presence(#xmlel{name = <<"iq">>, attrs = _, children = [C check_name_and_version_presence(_) -> false. -check_name_version_and_os_presence(#xmlel{name = <<"iq">>, attrs = _, children = [Child]}) -> +check_name_version_and_os_presence(#xmlel{name = <<"iq">>, children = [Child]}) -> case Child of #xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_SOFT_VERSION}], + attrs = #{<<"xmlns">> := ?NS_SOFT_VERSION}, children = Children} -> case Children of - [#xmlel{name = <<"name">>, attrs = [], children = [#xmlcdata{content = _}]}, - #xmlel{name = <<"version">>, attrs = [], children = [#xmlcdata{content = _}]}, - #xmlel{name = <<"os">>, attrs = [], children = [#xmlcdata{content = _}]}] -> + [#xmlel{name = <<"name">>, attrs = A1, + children = [#xmlcdata{content = _}]}, + #xmlel{name = <<"version">>, attrs = A2, + children = [#xmlcdata{content = _}]}, + #xmlel{name = <<"os">>, attrs = A3, + children = [#xmlcdata{content = _}]}] when ?IS_EMPTY(A1), + ?IS_EMPTY(A2), + ?IS_EMPTY(A3) -> true; _ -> false diff --git a/big_tests/tests/muc_SUITE.erl b/big_tests/tests/muc_SUITE.erl index cd2aaecad11..b9dc185cb1d 100644 --- a/big_tests/tests/muc_SUITE.erl +++ b/big_tests/tests/muc_SUITE.erl @@ -2888,7 +2888,7 @@ user_registration_errors(Config) -> %stanza_reserved_nickname_request() -> % escalus_stanza:iq(<<"get">>, [#xmlel{ % name = <<"query">>, -% attrs = [{<<"xmlns">>,<<"http://jabber.org/protocol/disco#info">>}, {<<"node">>, <<"x-roomuser-item">>}], +% attrs = #{<<"xmlns">> => <<"http://jabber.org/protocol/disco#info">>, <<"node">> => <<"x-roomuser-item">>}, % children = [] % }]). % @@ -4635,8 +4635,7 @@ wait_for_mam_result(RoomName, Client, Msg) -> stanza_room_list_request(_QueryId, RSM) -> escalus_stanza:iq(muc_host(), <<"get">>, [#xmlel{ name = <<"query">>, - attrs = [{<<"xmlns">>, - <<"http://jabber.org/protocol/disco#items">>}], + attrs = #{<<"xmlns">> => <<"http://jabber.org/protocol/disco#items">>}, children = skip_undefined([maybe_rsm_elem(RSM)]) }]). @@ -4644,7 +4643,7 @@ maybe_rsm_elem(undefined) -> undefined; maybe_rsm_elem(#rsm_in{max=Max, direction=Direction, id=Id, index=Index}) -> #xmlel{name = <<"set">>, - attrs = [{<<"xmlns">>, <<"http://jabber.org/protocol/rsm">>}], + attrs = #{<<"xmlns">> => <<"http://jabber.org/protocol/rsm">>}, children = skip_undefined([ maybe_rsm_max(Max), maybe_rsm_index(Index), @@ -4895,20 +4894,20 @@ print(Element) -> stanza_groupchat_enter_room(Room, Nick) -> stanza_to_room( escalus_stanza:presence(<<"available">>, - [#xmlel{name = <<"x">>, attrs = [{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}]}]), + [#xmlel{name = <<"x">>, attrs = #{<<"xmlns">> => <<"http://jabber.org/protocol/muc">>}}]), Room, Nick). stanza_groupchat_enter_room_no_nick(Room) -> stanza_to_room( escalus_stanza:presence(<<"available">>, - [#xmlel{name = <<"x">>, attrs = [{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}]}]), + [#xmlel{name = <<"x">>, attrs = #{<<"xmlns">> => <<"http://jabber.org/protocol/muc">>}}]), Room). stanza_muc_enter_password_protected_room(Room, Nick, Password) -> stanza_to_room( escalus_stanza:presence(<<"available">>, - [#xmlel{name = <<"x">>, attrs = [{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}], + [#xmlel{name = <<"x">>, attrs = #{<<"xmlns">> => <<"http://jabber.org/protocol/muc">>}, children = [#xmlel{name = <<"password">>, children = [#xmlcdata{content=[Password]}]} ]}]), Room, Nick). @@ -4944,11 +4943,11 @@ stanza_message_to_room(Room, Payload) -> stanza_private_muc_message(To, Msg) -> #xmlel{name = <<"message">>, - attrs = [{<<"to">>, To}, {<<"type">>, <<"chat">>}], + attrs = #{<<"to">> => To, <<"type">> => <<"chat">>}, children = [#xmlel{name = <<"body">>, children = [#xmlcdata{content = Msg}]}, #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, <<"http://jabber.org/protocol/muc#user">>}]}]}. + attrs = #{<<"xmlns">> => <<"http://jabber.org/protocol/muc#user">>}}]}. stanza_change_availability(NewStatus, Room, Nick) -> stanza_to_room( @@ -4963,13 +4962,13 @@ stanza_muc_enter_room_history_setting(Room, Nick, Setting, Value) -> stanza_to_room( escalus_stanza:presence( <<"available">>, [#xmlel{ name = <<"x">>, - attrs = [{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}], - children = [#xmlel{name= <<"history">>, attrs=[{Setting, Value}]}] }]), + attrs = #{<<"xmlns">> => <<"http://jabber.org/protocol/muc">>}, + children = [#xmlel{name= <<"history">>, attrs=#{Setting => Value}}] }]), Room, Nick). stanza_room_subject(Room, Subject) -> stanza_to_room(#xmlel{name = <<"message">>, - attrs = [{<<"type">>,<<"groupchat">>}], + attrs = #{<<"type">> => <<"groupchat">>}, children = [#xmlel{ name = <<"subject">>, children = [#xmlcdata{content = Subject}] @@ -4979,16 +4978,12 @@ stanza_room_subject(Room, Subject) -> stanza_direct_invitation(Room, Inviter, Invited) -> #xmlel{ name = <<"message">>, - attrs = [ - {<<"from">>, escalus_utils:get_jid(Inviter)}, - {<<"to">>, escalus_utils:get_short_jid(Invited)} - ], + attrs = #{<<"from">> => escalus_utils:get_jid(Inviter), + <<"to">> => escalus_utils:get_short_jid(Invited)}, children = [#xmlel{ name = <<"x">>, - attrs = [ - {<<"xmlns">>, ?NS_JABBER_X_CONF}, - {<<"jid">>, room_address(Room)} - ] + attrs = #{<<"xmlns">> => ?NS_JABBER_X_CONF, + <<"jid">> => room_address(Room)} }] }. @@ -4997,56 +4992,54 @@ stanza_mediated_invitation(Room, Invited) -> stanza_mediated_invitation_multi(Room, AllInvited) -> Payload = [ #xmlel{name = <<"invite">>, - attrs = [{<<"to">>, escalus_utils:get_short_jid(Invited)}]} + attrs = #{<<"to">> => escalus_utils:get_short_jid(Invited)}} || Invited <- AllInvited ], stanza_to_room(#xmlel{name = <<"message">>, children = [ #xmlel{ name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], + attrs = #{<<"xmlns">> => ?NS_MUC_USER}, children = Payload } ]}, Room). stanza_mediated_invitation_decline(Room,Sender) -> Payload = [ #xmlel{name = <<"decline">>, - attrs = [{<<"to">>, escalus_utils:get_short_jid(Sender)}]} ], + attrs = #{<<"to">> => escalus_utils:get_short_jid(Sender)}} ], stanza_to_room(#xmlel{name = <<"message">>, children = [ #xmlel{ name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], + attrs = #{<<"xmlns">> => ?NS_MUC_USER}, children = Payload } ]}, Room). stanza_set_roles(Room, List) -> - Payload = lists:map(fun({Nick, Role}) -> - #xmlel{name = <<"item">>, - attrs = [{<<"nick">>, Nick}, {<<"role">>, Role}]}; - ({Nick, Role, Reason}) -> - #xmlel{name = <<"item">>, - attrs = [{<<"nick">>, Nick}, {<<"role">>, Role}], - children = [#xmlel{ - name = <<"reason">>, - children = [#xmlcdata{content = Reason}]} - ]} - end, List), + Payload = lists:map( + fun({Nick, Role}) -> + #xmlel{name = <<"item">>, + attrs = #{<<"nick">> => Nick, <<"role">> => Role}}; + ({Nick, Role, Reason}) -> + #xmlel{name = <<"item">>, + attrs = #{<<"nick">> => Nick, <<"role">> => Role}, + children = [#xmlel{ name = <<"reason">>, + children = [#xmlcdata{content = Reason}]}]} + end, List), stanza_to_room(escalus_stanza:iq_set(?NS_MUC_ADMIN, Payload), Room). stanza_set_affiliations(Room, List) -> - Payload = lists:map(fun({JID, Affiliation}) -> - #xmlel{name = <<"item">>, - attrs = [{<<"jid">>, JID}, {<<"affiliation">>, Affiliation}]}; - ({JID, Affiliation, Reason}) -> - #xmlel{name = <<"item">>, - attrs = [{<<"jid">>, JID}, {<<"affiliation">>, Affiliation}], - children = [#xmlel{ - name = <<"reason">>, - children = [#xmlcdata{content = Reason}]} - ]} - end, List), + Payload = lists:map( + fun({JID, Affiliation}) -> + #xmlel{name = <<"item">>, + attrs = #{<<"jid">> => JID, <<"affiliation">> => Affiliation}}; + ({JID, Affiliation, Reason}) -> + #xmlel{name = <<"item">>, + attrs = #{<<"jid">> => JID, <<"affiliation">> => Affiliation}, + children = [#xmlel{name = <<"reason">>, + children = [#xmlcdata{content = Reason}]}]} + end, List), stanza_to_room(escalus_stanza:iq_set(?NS_MUC_ADMIN, Payload), Room). stanza_role_list_request(Room, Role) -> Payload = [ #xmlel{name = <<"item">>, - attrs = [{<<"role">>, Role}]} ], + attrs = #{<<"role">> => Role}} ], stanza_to_room(escalus_stanza:iq_get(?NS_MUC_ADMIN, Payload), Room). stanza_form_request(Room) -> @@ -5055,7 +5048,7 @@ stanza_form_request(Room) -> stanza_affiliation_list_request(Room, Affiliation) -> Payload = [ #xmlel{name = <<"item">>, - attrs = [{<<"affiliation">>, Affiliation}]} ], + attrs = #{<<"affiliation">> => Affiliation}} ], stanza_to_room(escalus_stanza:iq_get(?NS_MUC_ADMIN, Payload), Room). stanza_ban_list_request(Room) -> @@ -5071,7 +5064,7 @@ stanza_join_room(Room, Nick) -> stanza_to_room(#xmlel{name = <<"presence">>, children = [#xmlel{ name = <<"x">>, - attrs = [{<<"xmlns">>,<<"http://jabber.org/protocol/muc">>}] + attrs = #{<<"xmlns">> => <<"http://jabber.org/protocol/muc">>} }] },Room, Nick). @@ -5080,11 +5073,11 @@ stanza_join_room_many_x_elements(Room, Nick) -> stanza_to_room(#xmlel{name = <<"presence">>, children = [#xmlel{ name = <<"x">>, - attrs = [{<<"xmlns">>,<<"vcard-temp:x:update">>}] + attrs = #{<<"xmlns">> => <<"vcard-temp:x:update">>} }, #xmlel{ name = <<"x">>, - attrs = [{<<"xmlns">>,<<"http://jabber.org/protocol/muc">>}] + attrs = #{<<"xmlns">> => <<"http://jabber.org/protocol/muc">>} }] }, Room, Nick). diff --git a/big_tests/tests/muc_helper.erl b/big_tests/tests/muc_helper.erl index b7617f309a3..0b8b14e08b5 100644 --- a/big_tests/tests/muc_helper.erl +++ b/big_tests/tests/muc_helper.erl @@ -203,9 +203,10 @@ wait_for_process_down(Pid) -> end. stanza_muc_enter_room(Room, Nick) -> + Attrs = #{<<"xmlns">> => <<"http://jabber.org/protocol/muc">>}, stanza_to_room( escalus_stanza:presence( <<"available">>, - [#xmlel{ name = <<"x">>, attrs=[{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}]}]), + [#xmlel{ name = <<"x">>, attrs = Attrs}]), Room, Nick). stanza_default_muc_room(Room, Nick) -> diff --git a/big_tests/tests/muc_light_SUITE.erl b/big_tests/tests/muc_light_SUITE.erl index 050c25317fa..b9798950aa8 100644 --- a/big_tests/tests/muc_light_SUITE.erl +++ b/big_tests/tests/muc_light_SUITE.erl @@ -430,7 +430,7 @@ disco_rooms_rsm(Config) -> ProperJID = exml_query:attr(Item, <<"jid">>), RSM = #xmlel{ name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = [ #xmlel{ name = <<"max">>, children = [#xmlcdata{ content = <<"10">> }] }, #xmlel{ name = <<"before">> } ] }, @@ -446,7 +446,7 @@ disco_rooms_rsm(Config) -> BadAfter = #xmlel{ name = <<"after">>, children = [#xmlcdata{ content = <<"oops@muclight.localhost">> }] }, RSM2 = #xmlel{ name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = [ #xmlel{ name = <<"max">>, children = [#xmlcdata{ content = <<"10">> }] }, BadAfter ] }, @@ -1056,7 +1056,7 @@ verify_blocklist(Query, ProperBlocklist) -> BlockedRooms = exml_query:subelements(Query, <<"room">>), BlockedUsers = exml_query:subelements(Query, <<"user">>), BlockedItems = [{list_to_atom(binary_to_list(What)), list_to_atom(binary_to_list(Action)), Who} - || #xmlel{name = What, attrs = [{<<"action">>, Action}], + || #xmlel{name = What, attrs = #{<<"action">> := Action}, children = [#xmlcdata{ content = Who }]} <- BlockedRooms ++ BlockedUsers], ProperBlocklistLen = length(ProperBlocklist), diff --git a/big_tests/tests/muc_light_helper.erl b/big_tests/tests/muc_light_helper.erl index 7e1517fa640..0976824bfec 100644 --- a/big_tests/tests/muc_light_helper.erl +++ b/big_tests/tests/muc_light_helper.erl @@ -145,7 +145,7 @@ assert_archive_element({{message, Sender, Body}, Stanza}) -> assert_archive_element({{chat_marker, Type}, Stanza}) -> #forwarded_message{chat_marker = Type} = Stanza. -assert_valid_muc_roles_in_user_x([#xmlel{ attrs = [{<<"xmlns">>, ?NS_MUC_USER}] } = XUser | _]) -> +assert_valid_muc_roles_in_user_x([#xmlel{ attrs = #{<<"xmlns">> := ?NS_MUC_USER} } = XUser | _]) -> Item = exml_query:subelement(XUser, <<"item">>), muc_helper:assert_valid_affiliation(exml_query:attr(Item, <<"affiliation">>)), muc_helper:assert_valid_role(exml_query:attr(Item, <<"role">>)); @@ -244,7 +244,7 @@ stanza_create_room(RoomNode, InitConfig, InitOccupants) -> ConfigItem = #xmlel{ name = <<"configuration">>, children = [ kv_el(K, V) || {K, V} <- InitConfig ] }, OccupantsItems = [ #xmlel{ name = <<"user">>, - attrs = [{<<"affiliation">>, BinAff}], + attrs = #{<<"affiliation">> => BinAff}, children = [#xmlcdata{ content = BinJID }] } || {BinJID, BinAff} <- bin_aff_users(InitOccupants) ], OccupantsItem = #xmlel{ name = <<"occupants">>, children = OccupantsItems }, @@ -277,7 +277,7 @@ gc_message_verify_fun(Room, MsgText, Id) -> -spec stanza_aff_set(Room :: binary(), AffUsers :: ct_aff_users()) -> exml:element(). stanza_aff_set(Room, AffUsers) -> - Items = [#xmlel{ name = <<"user">>, attrs = [{<<"affiliation">>, AffBin}], + Items = [#xmlel{ name = <<"user">>, attrs = #{<<"affiliation">> => AffBin}, children = [#xmlcdata{ content = UserBin }] } || {UserBin, AffBin} <- bin_aff_users(AffUsers)], escalus_stanza:to(escalus_stanza:iq_set(?NS_MUC_LIGHT_AFFILIATIONS, Items), room_bin_jid(Room)). @@ -303,7 +303,7 @@ assert_no_aff_duplicates(AffUsers) -> -spec stanza_blocking_set(BlocklistChanges :: [ct_block_item()]) -> exml:element(). stanza_blocking_set(BlocklistChanges) -> Items = [#xmlel{ name = atom_to_binary(What), - attrs = [{<<"action">>, atom_to_binary(Action)}], + attrs = #{<<"action">> => atom_to_binary(Action)}, children = [#xmlcdata{ content = Who }] } || {What, Action, Who} <- BlocklistChanges], escalus_stanza:to(escalus_stanza:iq_set(?NS_MUC_LIGHT_BLOCKING, Items), muc_host()). diff --git a/big_tests/tests/muc_light_legacy_SUITE.erl b/big_tests/tests/muc_light_legacy_SUITE.erl index 28d3e34d06c..035ce8155cf 100644 --- a/big_tests/tests/muc_light_legacy_SUITE.erl +++ b/big_tests/tests/muc_light_legacy_SUITE.erl @@ -231,7 +231,7 @@ disco_rooms_rsm(Config) -> ProperJID = exml_query:attr(Item, <<"jid">>), RSM = #xmlel{ name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = [ #xmlel{ name = <<"max">>, children = [#xmlcdata{ content = <<"10">> }] }, #xmlel{ name = <<"before">> } ] }, @@ -247,7 +247,7 @@ disco_rooms_rsm(Config) -> BadAfter = #xmlel{ name = <<"after">>, children = [#xmlcdata{ content = <<"oops@", (?MUCHOST)/binary>> }] }, RSM2 = #xmlel{ name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = [ #xmlel{ name = <<"max">>, children = [#xmlcdata{ content = <<"10">> }] }, BadAfter ] }, @@ -283,7 +283,7 @@ change_subject(Config) -> escalus:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> Subject = <<"new subject">>, SubjectStanza = #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"groupchat">>}], + attrs = #{<<"type">> => <<"groupchat">>}, children = [#xmlel{ name = <<"subject">>, children = [#xmlcdata{content = Subject}] @@ -610,7 +610,7 @@ encode_privacy_item(What, Action, Who) -> stanza_create_room(RoomNode, Creator) -> ToBinJID = <<(room_bin_jid(RoomNode))/binary, $/, (lbin(escalus_client:short_jid(Creator)))/binary>>, - X = #xmlel{ name = <<"x">>, attrs = [{<<"xmlns">>, ?NS_MUC}] }, + X = #xmlel{ name = <<"x">>, attrs = #{<<"xmlns">> => ?NS_MUC} }, escalus_stanza:to(escalus_stanza:presence(<<"available">>, [X]), ToBinJID). -spec stanza_destroy_room(Room :: binary()) -> xmlel(). @@ -631,8 +631,8 @@ form_x_el(Fields) -> -spec stanza_aff_set(Room :: binary(), AffUsers :: ct_aff_users()) -> xmlel(). stanza_aff_set(Room, AffUsers) -> - Items = [#xmlel{ name = <<"item">>, attrs = [{<<"affiliation">>, AffBin}, - {<<"jid">>, UserBin}] } + Items = [#xmlel{ name = <<"item">>, attrs = #{<<"affiliation">> => AffBin, + <<"jid">> => UserBin} } || {UserBin, AffBin} <- bin_aff_users(AffUsers)], escalus_stanza:to(escalus_stanza:iq_set(?NS_MUC_ADMIN, Items), room_bin_jid(Room)). diff --git a/big_tests/tests/offline_SUITE.erl b/big_tests/tests/offline_SUITE.erl index ad57603a7fb..afef88ad89f 100644 --- a/big_tests/tests/offline_SUITE.erl +++ b/big_tests/tests/offline_SUITE.erl @@ -410,8 +410,8 @@ make_message_with_expiry(Target, Expiry, Text) -> Stanza = escalus_stanza:chat_to(Target, Text), #xmlel{children = Children} = Stanza, ExpiryElem = #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, <<"jabber:x:expire">>}, - {<<"seconds">>, ExpiryBin}]}, + attrs = #{<<"xmlns">> => <<"jabber:x:expire">>, + <<"seconds">> => ExpiryBin}}, Stanza#xmlel{children = [ExpiryElem | Children]}. repeat(_L, 0) -> []; diff --git a/big_tests/tests/pep_SUITE.erl b/big_tests/tests/pep_SUITE.erl index 3525f6358c9..b442100baed 100644 --- a/big_tests/tests/pep_SUITE.erl +++ b/big_tests/tests/pep_SUITE.erl @@ -481,7 +481,7 @@ add_config_to_create_node_request(#xmlel{children = [PubsubEl]} = Request) -> ConfigureEl = #xmlel{name = <<"configure">>, children = [Form]}, PubsubEl2 = PubsubEl#xmlel{children = PubsubEl#xmlel.children ++ [ConfigureEl]}, Request#xmlel{children = [PubsubEl2]}. - + publish_with_publish_options(Client, Node, Content, Options) -> publish_with_publish_options(Client, Node, Content, Options, ?NS_PUBSUB_PUB_OPTIONS). @@ -582,21 +582,21 @@ start_caps_clients(Config, [{UserSpec, Resource}]) -> feature_elems(PEPNodeNS) -> [#xmlel{name = <<"identity">>, - attrs = [{<<"category">>, <<"client">>}, - {<<"name">>, <<"Psi">>}, - {<<"type">>, <<"pc">>}]} | + attrs = #{<<"category">> => <<"client">>, + <<"name">> => <<"Psi">>, + <<"type">> => <<"pc">>}} | [feature_elem(F) || F <- features(PEPNodeNS)]]. feature_elem(F) -> #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, F}]}. + attrs = #{<<"var">> => F}}. caps(PEPNodeNS) -> #xmlel{name = <<"c">>, - attrs = [{<<"xmlns">>, ?NS_CAPS}, - {<<"hash">>, <<"sha-1">>}, - {<<"node">>, caps_node_name()}, - {<<"ver">>, caps_hash(PEPNodeNS)}]}. + attrs = #{<<"xmlns">> => ?NS_CAPS, + <<"hash">> => <<"sha-1">>, + <<"node">> => caps_node_name(), + <<"ver">> => caps_hash(PEPNodeNS)}}. features(PEPNodeNS) -> [?NS_DISCO_INFO, @@ -668,7 +668,7 @@ id(User, {NodeAddr, NodeName}, Suffix) -> item_content() -> #xmlel{name = <<"entry">>, - attrs = [{<<"xmlns">>, <<"http://www.w3.org/2005/Atom">>}]}. + attrs = #{<<"xmlns">> => <<"http://www.w3.org/2005/Atom">>}}. enable_sm(User) -> escalus_client:send(User, escalus_stanza:enable_sm()), diff --git a/big_tests/tests/presence_SUITE.erl b/big_tests/tests/presence_SUITE.erl index 1dac1c49c6d..ac7fb5d864a 100644 --- a/big_tests/tests/presence_SUITE.erl +++ b/big_tests/tests/presence_SUITE.erl @@ -133,7 +133,7 @@ available(Config) -> run_send_available_presence(Config, Presence). explicit_available(Config) -> - Presence = #xmlel{name = <<"presence">>, attrs = [{<<"type">>, <<"available">>}]}, + Presence = #xmlel{name = <<"presence">>, attrs = #{<<"type">> => <<"available">>}}, run_send_available_presence(Config, Presence). run_send_available_presence(Config, Presence) -> diff --git a/big_tests/tests/privacy_helper.erl b/big_tests/tests/privacy_helper.erl index 93bfd6659af..c48f779ebdd 100644 --- a/big_tests/tests/privacy_helper.erl +++ b/big_tests/tests/privacy_helper.erl @@ -82,15 +82,20 @@ does_privacy_list_children_match(Request, Result) -> ResultChildren = exml_query:subelements(exml_query:path(Result, ChildrenPath), <<"item">>), lists:all(fun do_items_match/1, lists:zip(RequestChildren, ResultChildren)). -do_items_match({#xmlel{attrs = Props1}, #xmlel{attrs = Props2}}) -> - L = [attr_match(Name, Value, Props2) || {Name, Value} <- Props1], +do_items_match({#xmlel{attrs = Attrs1}, #xmlel{attrs = Attrs2}}) -> + L = [attr_match(Name, Value, Attrs2) || Name := Value <- Attrs1], lists:all(fun(E) -> true == E end, L). -attr_match(<<"value">>, Value, Props) -> - ValueL = escalus_utils:jid_to_lower(Value), - ValueL == escalus_utils:jid_to_lower(proplists:get_value(<<"value">>, Props)); -attr_match(Name, Value, Props) -> - Value == proplists:get_value(Name, Props). +attr_match(Name, ValueL, Attrs) -> + case Attrs of + #{Name := ValueR} when Name =:= <<"value">> -> + escalus_utils:jid_to_lower(ValueL) == escalus_utils:jid_to_lower(ValueR); + #{Name := ValueR} -> + ValueL == ValueR; + _ -> + false + end. + %% Make the list the active one. activate_list(Client, ListName) -> diff --git a/big_tests/tests/private_SUITE.erl b/big_tests/tests/private_SUITE.erl index 95927a17eb6..a20d0302ec0 100644 --- a/big_tests/tests/private_SUITE.erl +++ b/big_tests/tests/private_SUITE.erl @@ -163,7 +163,7 @@ missing_ns(Config) -> my_banana(NS) -> #xmlel{ name = <<"my_element">>, - attrs = [{<<"xmlns">>, NS}], + attrs = #{<<"xmlns">> => NS}, children = [#xmlel{name = <<"banana">>}]}. check_body(Stanza, Names) -> diff --git a/big_tests/tests/pubsub_SUITE.erl b/big_tests/tests/pubsub_SUITE.erl index 166e36a9e77..05faa4fb84d 100644 --- a/big_tests/tests/pubsub_SUITE.erl +++ b/big_tests/tests/pubsub_SUITE.erl @@ -1989,23 +1989,23 @@ verify_item_retract({NodeAddr, NodeName}, ItemId, Stanza) -> escalus:assert(is_message, Stanza), NodeAddr = exml_query:attr(Stanza, <<"from">>), - [#xmlel{ attrs = [{<<"xmlns">>, ?NS_PUBSUB_EVENT}] } = Event] - = exml_query:subelements(Stanza, <<"event">>), + [#xmlel{ attrs = #{<<"xmlns">> := ?NS_PUBSUB_EVENT} } = Event] + = exml_query:subelements(Stanza, <<"event">>), - [#xmlel{ attrs = [{<<"node">>, NodeName}] } = Items] - = exml_query:subelements(Event, <<"items">>), + [#xmlel{ attrs = #{<<"node">> := NodeName} } = Items] + = exml_query:subelements(Event, <<"items">>), - [#xmlel{ attrs = [{<<"id">>, ItemId}] }] = exml_query:subelements(Items, <<"retract">>). + [#xmlel{ attrs = #{<<"id">> := ItemId} }] = exml_query:subelements(Items, <<"retract">>). verify_config_event({NodeAddr, NodeName}, ConfigChange, Stanza) -> escalus:assert(is_message, Stanza), NodeAddr = exml_query:attr(Stanza, <<"from">>), - [#xmlel{ attrs = [{<<"xmlns">>, ?NS_PUBSUB_EVENT}] } = Event] - = exml_query:subelements(Stanza, <<"event">>), + [#xmlel{ attrs = #{<<"xmlns">> := ?NS_PUBSUB_EVENT} } = Event] + = exml_query:subelements(Stanza, <<"event">>), - [#xmlel{ attrs = [{<<"node">>, NodeName}] } = ConfigEl] - = exml_query:subelements(Event, <<"configuration">>), + [#xmlel{ attrs = #{<<"node">> := NodeName} } = ConfigEl] + = exml_query:subelements(Event, <<"configuration">>), Fields = exml_query:paths(ConfigEl, [{element, <<"x">>}, {element, <<"field">>}]), diff --git a/big_tests/tests/pubsub_tools.erl b/big_tests/tests/pubsub_tools.erl index 6ad4ca6e4ac..40d74181ee2 100644 --- a/big_tests/tests/pubsub_tools.erl +++ b/big_tests/tests/pubsub_tools.erl @@ -56,7 +56,8 @@ create_node(User, Node, Options) -> #xmlel{children = [ #xmlel{children = [CreateEl | OtherEls]} = PubsubEl ]} = IQ = Request0, - NewCreateEl = CreateEl#xmlel{attrs = [{<<"type">>, Type} | CreateEl#xmlel.attrs]}, + Attrs = CreateEl#xmlel.attrs, + NewCreateEl = CreateEl#xmlel{attrs = Attrs#{<<"type">> => Type}}, NewPubsubEl = PubsubEl#xmlel{children = [NewCreateEl | OtherEls]}, IQ#xmlel{children = [NewPubsubEl]} end, @@ -120,7 +121,7 @@ publish_without_node_attr(User, ItemId, Node, Options) -> Request = publish_request(Id, User, ItemId, Node, Options), [PubSubEl] = Request#xmlel.children, [PublishEl] = PubSubEl#xmlel.children, - PublishElDefect = PublishEl#xmlel{ attrs = [] }, + PublishElDefect = PublishEl#xmlel{ attrs = #{} }, RequestDefect = Request#xmlel{ children = [PubSubEl#xmlel{ children = [PublishElDefect] }] }, send_request_and_receive_response(User, RequestDefect, Id, Options). @@ -574,7 +575,7 @@ id(User, {NodeAddr, NodeName}, Suffix) -> item_content() -> #xmlel{name = <<"entry">>, - attrs = [{<<"xmlns">>, <<"http://www.w3.org/2005/Atom">>}]}. + attrs = #{<<"xmlns">> => <<"http://www.w3.org/2005/Atom">>}}. decode_config_form(IQResult) -> decode_form(IQResult, ?NS_PUBSUB_OWNER, <<"configure">>). diff --git a/big_tests/tests/push_SUITE.erl b/big_tests/tests/push_SUITE.erl index 22e1e01b1ba..7438e94a3ce 100644 --- a/big_tests/tests/push_SUITE.erl +++ b/big_tests/tests/push_SUITE.erl @@ -174,10 +174,10 @@ enable_should_fail_with_missing_attributes(Config) -> %% Sending only one attribute should fail lists:foreach( - fun(Attr) -> + fun({K, V}) -> escalus:send(Bob, escalus_stanza:iq(<<"set">>, [#xmlel{name = <<"enable">>, - attrs = [Attr]}])), + attrs = #{K => V}}])), escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], escalus:wait_for_stanza(Bob)) end, CorrectAttrs), @@ -185,9 +185,10 @@ enable_should_fail_with_missing_attributes(Config) -> %% Sending all but one attribute should fail lists:foreach( fun(Attr) -> + Attrs = #{K => V || {K, V} <- CorrectAttrs -- [Attr]}, escalus:send(Bob, escalus_stanza:iq(<<"set">>, [#xmlel{name = <<"enable">>, - attrs = CorrectAttrs -- [Attr]}])), + attrs = Attrs}])), escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], escalus:wait_for_stanza(Bob)) end, CorrectAttrs), @@ -276,10 +277,10 @@ disable_should_fail_with_missing_attributes(Config) -> %% Sending only one attribute should fail lists:foreach( - fun(Attr) -> + fun({K,V}) -> escalus:send(Bob, escalus_stanza:iq(<<"set">>, [#xmlel{name = <<"disable">>, - attrs = [Attr]}])), + attrs = #{K => V}}])), escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], escalus:wait_for_stanza(Bob)) end, CorrectAttrs), diff --git a/big_tests/tests/push_helper.erl b/big_tests/tests/push_helper.erl index 1d071ba9f88..6148561f7c6 100644 --- a/big_tests/tests/push_helper.erl +++ b/big_tests/tests/push_helper.erl @@ -12,20 +12,16 @@ ns_pubsub_pub_options() -> <<"http://jabber.org/protocol/pubsub#publish-options" push_form_type()-> <<"urn:xmpp:push:summary">>. disable_stanza(JID, undefined) -> - disable_stanza([ - {<<"xmlns">>, <<"urn:xmpp:push:0">>}, - {<<"jid">>, JID} - ]); + disable_stanza(#{<<"xmlns">> => <<"urn:xmpp:push:0">>, + <<"jid">> => JID}); disable_stanza(JID, Node) -> - disable_stanza([ - {<<"xmlns">>, <<"urn:xmpp:push:0">>}, - {<<"jid">>, JID}, - {<<"node">>, Node} - ]). + disable_stanza(#{<<"xmlns">> => <<"urn:xmpp:push:0">>, + <<"jid">> => JID, + <<"node">> => Node}). disable_stanza(JID) when is_binary(JID) -> disable_stanza(JID, undefined); -disable_stanza(Attrs) when is_list(Attrs) -> +disable_stanza(Attrs) when is_map(Attrs) -> escalus_stanza:iq(<<"set">>, [#xmlel{name = <<"disable">>, attrs = Attrs}]). enable_stanza(JID, Node) -> @@ -33,11 +29,11 @@ enable_stanza(JID, Node) -> enable_stanza(JID, Node, FormFields) -> enable_stanza(JID, Node, FormFields, ns_pubsub_pub_options()). enable_stanza(JID, Node, FormFields, FormType) -> - escalus_stanza:iq(<<"set">>, [#xmlel{name = <<"enable">>, attrs = [ - {<<"xmlns">>, <<"urn:xmpp:push:0">>}, - {<<"jid">>, JID}, - {<<"node">>, Node} - ], children = maybe_form(FormFields, FormType)}]). + escalus_stanza:iq(<<"set">>, [#xmlel{name = <<"enable">>, attrs = #{ + <<"xmlns">> => <<"urn:xmpp:push:0">>, + <<"jid">> => JID, + <<"node">> => Node + }, children = maybe_form(FormFields, FormType)}]). maybe_form(undefined, _FormType) -> []; diff --git a/big_tests/tests/push_http_SUITE.erl b/big_tests/tests/push_http_SUITE.erl index 1a96b5e87ca..6aabf6b410e 100644 --- a/big_tests/tests/push_http_SUITE.erl +++ b/big_tests/tests/push_http_SUITE.erl @@ -180,10 +180,10 @@ stop_pool() -> rpc(mongoose_wpool, stop, [http, <<"localhost">>, http_pool]). setup_modules() -> - {Mod, Code} = dynamic_compile:from_string(custom_module_code()), - rpc(code, load_binary, [Mod, "mod_event_pusher_http_custom.erl", Code]), - {Mod2, Code2} = dynamic_compile:from_string(custom_module_code_2()), - rpc(code, load_binary, [Mod2, "mod_event_pusher_http_custom_2.erl", Code2]), + {Module1, Binary1, Filename1} = code:get_object_code(mod_event_pusher_http_custom) , + rpc(code, load_binary, [Module1, Filename1, Binary1]), + {Module2, Binary2, Filename2} = code:get_object_code(mod_event_pusher_http_custom_2) , + rpc(code, load_binary, [Module2, Filename2, Binary2]), ok. teardown_modules() -> @@ -192,37 +192,6 @@ teardown_modules() -> rpc(M, F, A) -> distributed_helper:rpc(distributed_helper:mim(), M, F, A). -custom_module_code() -> - "-module(mod_event_pusher_http_custom). - -export([should_make_req/6, prepare_body/7, prepare_headers/7]). - should_make_req(Acc, _, _, _, _, _) -> - case mongoose_acc:stanza_name(Acc) of - <<\"message\">> -> true; - _ -> false - end. - prepare_headers(_, _, _, _, _, _, _) -> - mod_event_pusher_http_defaults:prepare_headers(x, x, x, x, x, x, x). - prepare_body(_Acc, Dir, _Host, Message, _Sender, _Receiver, _Opts) -> - <<(atom_to_binary(Dir, utf8))/binary, $-, Message/binary>>. - " -. - -custom_module_code_2() -> - "-module(mod_event_pusher_http_custom_2). - -export([should_make_req/6, prepare_body/7, prepare_headers/7]). - should_make_req(Acc, out, _, _, _, _) -> - case mongoose_acc:stanza_name(Acc) of - <<\"message\">> -> true; - _ -> false - end; - should_make_req(_, in, _, _, _, _) -> false. - prepare_headers(_, _, _, _, _, _, _) -> - mod_event_pusher_http_defaults:prepare_headers(x, x, x, x, x, x, x). - prepare_body(_Acc, Dir, _Host, Message, _Sender, _Receiver, _Opts) -> - <<$2, $-, (atom_to_binary(Dir, utf8))/binary, $-, Message/binary>>. - " - . - send(Alice, Bob, Body) -> Stanza = escalus_stanza:chat_to(Bob, Body), escalus_client:send(Alice, Stanza). diff --git a/big_tests/tests/push_integration_SUITE.erl b/big_tests/tests/push_integration_SUITE.erl index 9d4d6e53ff5..2e850ec56f0 100644 --- a/big_tests/tests/push_integration_SUITE.erl +++ b/big_tests/tests/push_integration_SUITE.erl @@ -942,10 +942,10 @@ enable_push_for_user(User, Service, EnableOpts, MockResponse, Config) -> add_user_server_to_whitelist(User, {NodeAddr, NodeName}) -> AffList = [ #xmlel{ name = <<"affiliation">>, - attrs = [{<<"jid">>, escalus_utils:get_server(User)}, - {<<"affiliation">>, <<"publish-only">>}] } + attrs = #{<<"jid">> => escalus_utils:get_server(User), + <<"affiliation">> => <<"publish-only">>} } ], - Affiliations = #xmlel{ name = <<"affiliations">>, attrs = [{<<"node">>, NodeName}], + Affiliations = #xmlel{ name = <<"affiliations">>, attrs = #{<<"node">> => NodeName}, children = AffList }, Id = base64:encode(crypto:strong_rand_bytes(5)), Stanza = escalus_pubsub_stanza:pubsub_owner_iq(<<"set">>, User, Id, NodeAddr, [Affiliations]), diff --git a/big_tests/tests/push_pubsub_SUITE.erl b/big_tests/tests/push_pubsub_SUITE.erl index e5ff372a7dd..5fb303c215f 100644 --- a/big_tests/tests/push_pubsub_SUITE.erl +++ b/big_tests/tests/push_pubsub_SUITE.erl @@ -126,8 +126,8 @@ publish_fails_with_invalid_item(Config) -> Item = #xmlel{name = <<"invalid-item">>, - attrs = [{<<"xmlns">>, ?NS_PUSH}]}, - + attrs = #{<<"xmlns">> => ?NS_PUSH}}, + Options = [ {<<"device_id">>, <<"sometoken">>}, {<<"service">>, <<"apns">>} @@ -158,7 +158,7 @@ publish_fails_with_no_options(Config) -> Item = #xmlel{name = <<"notification">>, - attrs = [{<<"xmlns">>, ?NS_PUSH}], + attrs = #{<<"xmlns">> => ?NS_PUSH}, children = push_helper:maybe_form(ContentFields, ?PUSH_FORM_TYPE)}, Publish = escalus_pubsub_stanza:publish(Alice, <<"itemid">>, Item, <<"id">>, Node), @@ -360,7 +360,7 @@ setup_pubsub(User) -> publish_iq(Client, Node, Content, Options) -> Item = #xmlel{name = <<"notification">>, - attrs = [{<<"xmlns">>, ?NS_PUSH}], + attrs = #{<<"xmlns">> => ?NS_PUSH}, children = push_helper:maybe_form(Content, ?PUSH_FORM_TYPE)}, OptionsEl = #xmlel{name = <<"publish-options">>, diff --git a/big_tests/tests/race_conditions_SUITE.erl b/big_tests/tests/race_conditions_SUITE.erl index 159fc5fdb0b..96404cd5f78 100644 --- a/big_tests/tests/race_conditions_SUITE.erl +++ b/big_tests/tests/race_conditions_SUITE.erl @@ -160,7 +160,7 @@ delayiq_ns() -> delayiq_iq() -> BinCallerPid = encode_pid(self()), Payload = #xmlel{name = <<"data">>, - attrs = [{<<"caller_pid">>, BinCallerPid}]}, + attrs = #{<<"caller_pid">> => BinCallerPid}}, escalus_stanza:iq_get(delayiq_ns(), [Payload]). %% This function is executed by MongooseIM diff --git a/big_tests/tests/rest_SUITE.erl b/big_tests/tests/rest_SUITE.erl index 63721657fa4..ddde9970e5c 100644 --- a/big_tests/tests/rest_SUITE.erl +++ b/big_tests/tests/rest_SUITE.erl @@ -281,7 +281,7 @@ stanzas_are_sent_and_received(Config) -> escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> AliceJid = escalus_client:full_jid(Alice), BobJid = escalus_client:full_jid(Bob), - Stanza = extended_message([{<<"from">>, AliceJid}, {<<"to">>, BobJid}]), + Stanza = extended_message(#{<<"from">> => AliceJid, <<"to">> => BobJid}), {?NOCONTENT, _} = send_stanza(Stanza), Res = escalus:wait_for_stanza(Bob), ?assertEqual(<<"attribute">>, exml_query:attr(Res, <<"extra">>)), @@ -294,19 +294,19 @@ stanza_errors(Config) -> BobJid = escalus_users:get_jid(Config1, bob), UnknownJid = <<"baduser@", (domain())/binary>>, {?BAD_REQUEST, <<"Missing recipient JID">>} = - send_stanza(extended_message([{<<"from">>, AliceJid}])), + send_stanza(extended_message(#{<<"from">> => AliceJid})), {?BAD_REQUEST, <<"Missing sender JID">>} = - send_stanza(extended_message([{<<"to">>, BobJid}])), + send_stanza(extended_message(#{<<"to">> => BobJid})), {?BAD_REQUEST, <<"Invalid recipient JID">>} = - send_stanza(extended_message([{<<"from">>, AliceJid}, {<<"to">>, <<"@invalid">>}])), + send_stanza(extended_message(#{<<"from">> => AliceJid, <<"to">> => <<"@invalid">>})), {?BAD_REQUEST, <<"Invalid sender JID">>} = - send_stanza(extended_message([{<<"from">>, <<"@invalid">>}, {<<"to">>, BobJid}])), + send_stanza(extended_message(#{<<"from">> => <<"@invalid">>, <<"to">> => BobJid})), {?BAD_REQUEST, <<"User's domain does not exist">>} = - send_stanza(extended_message([{<<"from">>, <<"baduser@baddomain">>}, {<<"to">>, BobJid}])), + send_stanza(extended_message(#{<<"from">> => <<"baduser@baddomain">>, <<"to">> => BobJid})), {?BAD_REQUEST, <<"User does not exist">>} = - send_stanza(extended_message([{<<"from">>, UnknownJid}, {<<"to">>, BobJid}])), + send_stanza(extended_message(#{<<"from">> => UnknownJid, <<"to">> => BobJid})), {?BAD_REQUEST, <<"Malformed stanza">>} = - send_stanza(broken_message([{<<"from">>, AliceJid}, {<<"to">>, BobJid}])), + send_stanza(broken_message(#{<<"from">> => AliceJid, <<"to">> => BobJid})), {?BAD_REQUEST, <<"Missing stanza">>} = post(admin, <<"/stanzas">>, #{}). @@ -656,7 +656,7 @@ remove_last_character(Bin) -> extended_message(Attrs) -> M = #xmlel{name = <<"message">>, - attrs = [{<<"extra">>, <<"attribute">>} | Attrs], + attrs = Attrs#{<<"extra">> => <<"attribute">>}, children = [#xmlel{name = <<"body">>, children = [#xmlcdata{content = <<"the body">>}]}, #xmlel{name = <<"sibling">>, diff --git a/big_tests/tests/s2s_SUITE.erl b/big_tests/tests/s2s_SUITE.erl index 64392457e87..dd9260c805a 100644 --- a/big_tests/tests/s2s_SUITE.erl +++ b/big_tests/tests/s2s_SUITE.erl @@ -442,7 +442,7 @@ s2s_start_stream(Conn = #client{props = Props}, []) -> StreamStartRep = s2s_start_stream_and_wait_for_response(Conn), #xmlstreamstart{attrs = Attrs} = StreamStartRep, - Id = proplists:get_value(<<"id">>, Attrs), + Id = maps:get(<<"id">>, Attrs, undefined), escalus_session:stream_features(Conn#client{props = [{sid, Id} | Props]}, []). @@ -452,9 +452,10 @@ s2s_start_stream_and_wait_for_response(Conn = #client{props = Props}) -> escalus_connection:get_stanza(Conn, wait_for_stream). s2s_stream_start_stanza(Props, F) -> - Attrs = (stream_start_attrs())#{<<"to">> => proplists:get_value(to_server, Props), - <<"from">> => proplists:get_value(from_server, Props)}, - #xmlstreamstart{name = <<"stream:stream">>, attrs = maps:to_list(F(Attrs))}. + Attrs0 = stream_start_attrs(), + Attrs = Attrs0#{<<"to">> => proplists:get_value(to_server, Props), + <<"from">> => proplists:get_value(from_server, Props)}, + #xmlstreamstart{name = <<"stream:stream">>, attrs = F(Attrs)}. stream_start_attrs() -> #{<<"xmlns">> => <<"jabber:server">>, diff --git a/big_tests/tests/sasl2_SUITE.erl b/big_tests/tests/sasl2_SUITE.erl index 3866ef13809..65068e8d648 100644 --- a/big_tests/tests/sasl2_SUITE.erl +++ b/big_tests/tests/sasl2_SUITE.erl @@ -115,7 +115,7 @@ server_announces_sasl2_with_some_mechanism_and_inline_sm(Config) -> authenticate_stanza_has_invalid_mechanism(Config) -> Steps = [start_new_user, send_invalid_mech_auth_stanza], #{answer := Response} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"failure">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Response). + ?assertMatch(#xmlel{name = <<"failure">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Response). user_agent_is_invalid(Config) -> Steps = [start_new_user, send_bad_user_agent], @@ -137,7 +137,7 @@ authenticate_with_plain_and_user_agent_without_id(Config) -> auth_with_plain(Steps, Config) -> #{answer := Success, features := Features} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"success">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Success), + ?assertMatch(#xmlel{name = <<"success">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Success), CData = exml_query:path(Success, [{element, <<"additional-data">>}, cdata], <<>>), ?assert(is_binary(CData) andalso 0 =< byte_size(CData)), Identifier = exml_query:path(Success, [{element, <<"authorization-identifier">>}, cdata], <<>>), @@ -147,7 +147,7 @@ auth_with_plain(Steps, Config) -> authenticate_with_scram_abort(Config) -> Steps = [start_new_user, scram_step_1, scram_abort], #{answer := Response} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"failure">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Response), + ?assertMatch(#xmlel{name = <<"failure">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Response), Aborted = exml_query:path(Response, [{element_with_ns, <<"aborted">>, ?NS_SASL}]), ?assertNotEqual(undefined, Aborted). @@ -164,7 +164,7 @@ authenticate_with_scram_bad_response(Config) -> authenticate_with_scram(Config) -> Steps = [start_new_user, scram_step_1, scram_step_2, receive_features], #{answer := Success, features := Features} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"success">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Success), + ?assertMatch(#xmlel{name = <<"success">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Success), CData = exml_query:path(Success, [{element, <<"additional-data">>}, cdata], <<>>), ?assert(is_binary(CData) andalso 0 =< byte_size(CData)), Identifier = exml_query:path(Success, [{element, <<"authorization-identifier">>}, cdata], <<>>), @@ -180,7 +180,7 @@ sm_failure_missing_previd_does_not_stop_sasl2(Config) -> Steps = [create_user, buffer_messages_and_die, connect_tls, start_stream_get_features, auth_with_resumption_missing_previd, receive_features], #{answer := Success} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"success">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Success), + ?assertMatch(#xmlel{name = <<"success">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Success), Resumed = exml_query:path(Success, [{element_with_ns, <<"failed">>, ?NS_STREAM_MGNT_3}]), escalus:assert(is_sm_failed, [<<"bad-request">>], Resumed). @@ -188,7 +188,7 @@ sm_failure_invalid_h_does_not_stop_sasl2(Config) -> Steps = [create_user, buffer_messages_and_die, connect_tls, start_stream_get_features, auth_with_resumption_invalid_h, receive_features], #{answer := Success} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"success">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Success), + ?assertMatch(#xmlel{name = <<"success">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Success), Resumed = exml_query:path(Success, [{element_with_ns, <<"failed">>, ?NS_STREAM_MGNT_3}]), escalus:assert(is_sm_failed, [<<"bad-request">>], Resumed). @@ -196,7 +196,7 @@ sm_failure_exceeding_h_does_not_stop_sasl2(Config) -> Steps = [create_user, buffer_messages_and_die, connect_tls, start_stream_get_features, auth_with_resumption_exceeding_h, receive_features], #{answer := Success} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"success">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Success), + ?assertMatch(#xmlel{name = <<"success">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Success), Resumed = exml_query:path(Success, [{element_with_ns, <<"failed">>, ?NS_STREAM_MGNT_3}]), escalus:assert(is_sm_failed, [<<"bad-request">>], Resumed). @@ -204,7 +204,7 @@ sm_failure_unknown_smid_does_not_stop_sasl2(Config) -> Steps = [create_user, buffer_messages_and_die, connect_tls, start_stream_get_features, auth_with_resumption_unknown_smid, receive_features], #{answer := Success} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"success">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Success), + ?assertMatch(#xmlel{name = <<"success">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Success), Resumed = exml_query:path(Success, [{element_with_ns, <<"failed">>, ?NS_STREAM_MGNT_3}]), escalus:assert(is_sm_failed, [<<"item-not-found">>], Resumed). @@ -212,6 +212,6 @@ sm_is_bound_at_sasl2_success(Config) -> Steps = [create_user, buffer_messages_and_die, connect_tls, start_stream_get_features, auth_with_resumption, has_no_more_stanzas, can_send_messages], #{answer := Success, smid := SMID} = sasl2_helper:apply_steps(Steps, Config), - ?assertMatch(#xmlel{name = <<"success">>, attrs = [{<<"xmlns">>, ?NS_SASL_2}]}, Success), + ?assertMatch(#xmlel{name = <<"success">>, attrs = #{<<"xmlns">> := ?NS_SASL_2}}, Success), Resumed = exml_query:path(Success, [{element_with_ns, <<"resumed">>, ?NS_STREAM_MGNT_3}]), ?assert(escalus_pred:is_sm_resumed(SMID, Resumed)). diff --git a/big_tests/tests/sasl2_helper.erl b/big_tests/tests/sasl2_helper.erl index e33c893f28a..2a7376e7c29 100644 --- a/big_tests/tests/sasl2_helper.erl +++ b/big_tests/tests/sasl2_helper.erl @@ -103,15 +103,15 @@ auth_with_resumption(Config, Client, #{smid := SMID, texts := Texts} = Data) -> auth_with_resumption_invalid_h(Config, Client, #{smid := SMID} = Data) -> Resume = #xmlel{name = <<"resume">>, - attrs = [{<<"xmlns">>, ?NS_STREAM_MGNT_3}, - {<<"previd">>, SMID}, - {<<"h">>, <<"aaa">>}]}, + attrs = #{<<"xmlns">> => ?NS_STREAM_MGNT_3, + <<"previd">> => SMID, + <<"h">> => <<"aaa">>}}, plain_auth(Config, Client, Data, [Resume]). auth_with_resumption_missing_previd(Config, Client, Data) -> Resume = #xmlel{name = <<"resume">>, - attrs = [{<<"xmlns">>, ?NS_STREAM_MGNT_3}, - {<<"h">>, <<"aaa">>}]}, + attrs = #{<<"xmlns">> => ?NS_STREAM_MGNT_3, + <<"h">> => <<"aaa">>}}, plain_auth(Config, Client, Data, [Resume]). auth_with_resumption_exceeding_h(Config, Client, #{smid := SMID} = Data) -> @@ -226,7 +226,7 @@ auth_elem(Mech, Children) -> auth_elem(Mech, NS, Children) -> #xmlel{name = <<"authenticate">>, - attrs = [{<<"xmlns">>, NS}, {<<"mechanism">>, Mech}], + attrs = #{<<"xmlns">> => NS, <<"mechanism">> => Mech}, children = Children}. plain_auth_initial_response(#client{props = Props}) -> @@ -245,7 +245,7 @@ response_elem(Response) -> response_elem(Response, NS) -> #xmlel{name = <<"response">>, - attrs = [{<<"xmlns">>, NS}], + attrs = #{<<"xmlns">> => NS}, children = [#xmlcdata{content = base64:encode(Response)}]}. abort_elem() -> @@ -253,7 +253,7 @@ abort_elem() -> abort_elem(NS) -> #xmlel{name = <<"abort">>, - attrs = [{<<"xmlns">>, NS}], + attrs = #{<<"xmlns">> => NS}, children = []}. user_agent_elem_without_id() -> @@ -279,5 +279,5 @@ user_agent_elem(Id, Software, Device) -> || Value <- [Software], Value =/= undefined ], DeviEl = [#xmlel{name = <<"device">>, children = [#xmlcdata{content = Value}]} || Value <- [Device], Value =/= undefined ], - Attrs = [{<<"id">>, Value} || Value <- [Id], Value =/= undefined ], + Attrs = #{<<"id">> => Value || Value <- [Id], Value =/= undefined}, #xmlel{name = <<"user-agent">>, attrs = Attrs, children = SoftEl ++ DeviEl}. diff --git a/big_tests/tests/sic_SUITE.erl b/big_tests/tests/sic_SUITE.erl index 35096b76e6d..4667e96fcac 100644 --- a/big_tests/tests/sic_SUITE.erl +++ b/big_tests/tests/sic_SUITE.erl @@ -109,7 +109,7 @@ is_sic_response() -> sic_iq_get() -> escalus_stanza:iq(<<"get">>, [#xmlel{ name = <<"address">>, - attrs = [{<<"xmlns">>, ?NS_SIC}], + attrs = #{<<"xmlns">> => ?NS_SIC}, children = [] }]). diff --git a/big_tests/tests/sm_SUITE.erl b/big_tests/tests/sm_SUITE.erl index 0d1219193bf..34aa0d99574 100644 --- a/big_tests/tests/sm_SUITE.erl +++ b/big_tests/tests/sm_SUITE.erl @@ -439,7 +439,7 @@ h_ok_after_a_chat(ConfigIn) -> h_non_given_closes_stream_gracefully(ConfigIn) -> AStanza = #xmlel{name = <<"a">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:sm:3">>}]}, + attrs = #{<<"xmlns">> => <<"urn:xmpp:sm:3">>}}, Config = escalus_users:update_userspec(ConfigIn, ?config(user, ConfigIn), stream_management, true), escalus:fresh_story(Config, [{?config(user, Config), 1}], fun(User) -> @@ -1045,9 +1045,10 @@ resume_session_with_wrong_sid_returns_item_not_found(Config) -> resume_session_with_wrong_namespace_is_a_noop(Config) -> User = connect_fresh(Config, ?config(user, Config), auth), - #xmlel{attrs = Attrs} = Resume = escalus_stanza:resume(<<"doesnt_matter">>, 4), - Attrs2 = lists:keyreplace(<<"xmlns">>, 1, Attrs, {<<"xmlns">>, <<"not-stream-mgnt">>}), - escalus_connection:send(User, Resume#xmlel{attrs = Attrs2}), + Resume = escalus_stanza:resume(<<"doesnt_matter">>, 4), + Attrs = Resume#xmlel.attrs, + NewAttrs = Attrs#{<<"xmlns">> => <<"not-stream-mgnt">>}, + escalus_connection:send(User, Resume#xmlel{attrs = NewAttrs}), escalus_assert:has_no_stanzas(User), [] = sm_helper:get_user_present_resources(User), true = escalus_connection:is_connected(User), @@ -1460,7 +1461,7 @@ get_stanzas_filtered_by_mod_ping() -> check_stanzas_filtered_by_mod_ping() -> Stanzas = get_stanzas_filtered_by_mod_ping(), - lists:foreach(fun(Stanza) -> + lists:foreach(fun(Stanza) -> escalus:assert(is_iq_error, Stanza), ?assertNotEqual(undefined, exml_query:subelement_with_name_and_ns(Stanza, <<"ping">>, <<"urn:xmpp:ping">>)) diff --git a/big_tests/tests/smart_markers_SUITE.erl b/big_tests/tests/smart_markers_SUITE.erl index 845e7582e86..deabfff7dd1 100644 --- a/big_tests/tests/smart_markers_SUITE.erl +++ b/big_tests/tests/smart_markers_SUITE.erl @@ -138,7 +138,7 @@ error_set_iq(Config) -> error_bad_peer(Config) -> escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> - Iq = iq_fetch_marker([{<<"peer">>, <<"/@">>}]), + Iq = iq_fetch_marker(#{<<"peer">> => <<"/@">>}), escalus:send(Alice, Iq), Response = escalus:wait_for_stanza(Alice), escalus:assert(is_iq_error, [Iq], Response) @@ -146,7 +146,7 @@ error_bad_peer(Config) -> error_no_peer_given(Config) -> escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> - Iq = iq_fetch_marker([]), + Iq = iq_fetch_marker(#{}), escalus:send(Alice, Iq), Response = escalus:wait_for_stanza(Alice), escalus:assert(is_iq_error, [Iq], Response) @@ -155,7 +155,7 @@ error_no_peer_given(Config) -> error_bad_timestamp(Config) -> escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> PeerJid = <<"peer@localhost">>, - Iq = iq_fetch_marker([{<<"peer">>, PeerJid}, {<<"after">>, <<"baddate">>}]), + Iq = iq_fetch_marker(#{<<"peer">> => PeerJid, <<"after">> => <<"baddate">>}), escalus:send(Alice, Iq), Response = escalus:wait_for_stanza(Alice), escalus:assert(is_iq_error, [Iq], Response) @@ -391,19 +391,19 @@ verify_marker_fetch(MarkingUser, MarkedUser) -> verify_marker_fetch(MarkingUser, MarkedUser, undefined, undefined). verify_marker_fetch(MarkingUser, MarkedUser, Thread, After) -> - MarkedUserBJid = case is_binary(MarkedUser) of - true -> [{<<"peer">>, MarkedUser}]; - false -> [{<<"peer">>, escalus_utils:jid_to_lower(escalus_client:short_jid(MarkedUser))}] - end, - MaybeThread = case Thread of - undefined -> []; - _ -> [{<<"thread">>, Thread}] - end, - MaybeAfter = case After of - undefined -> []; - _ -> [{<<"after">>, After}] - end, - Iq = iq_fetch_marker(MarkedUserBJid ++ MaybeThread ++ MaybeAfter), + Attrs0 = case is_binary(MarkedUser) of + true -> #{<<"peer">> => MarkedUser}; + false -> #{<<"peer">> => escalus_utils:jid_to_lower(escalus_client:short_jid(MarkedUser))} + end, + Attrs1 = case Thread of + undefined -> Attrs0; + _ -> Attrs0#{<<"thread">> => Thread} + end, + Attrs2 = case After of + undefined -> Attrs1; + _ -> Attrs1#{<<"after">> => After} + end, + Iq = iq_fetch_marker(Attrs2), %% using wait_until to ensure that assertions are eventually passing wait_helper:wait_until( fun() -> @@ -425,7 +425,7 @@ verify_marker_fetch(MarkingUser, MarkedUser, Thread, After) -> verify_marker_fetch_is_empty(MarkingUser, MarkedUser) -> MarkedUserBJid = escalus_utils:jid_to_lower(escalus_client:short_jid(MarkedUser)), - Iq = iq_fetch_marker([{<<"peer">>, MarkedUserBJid}]), + Iq = iq_fetch_marker(#{<<"peer">> => MarkedUserBJid}), escalus:send(MarkingUser, Iq), Response = escalus:wait_for_stanza(MarkingUser), escalus:assert(is_iq_result, [Iq], Response), diff --git a/big_tests/tests/special_chars_helper.erl b/big_tests/tests/special_chars_helper.erl index e1cb4a8d521..44475a4889d 100644 --- a/big_tests/tests/special_chars_helper.erl +++ b/big_tests/tests/special_chars_helper.erl @@ -28,4 +28,4 @@ add_special_chars_attr_xmlel(BaseMessage, SpecialCharsChild) -> create_special_chars_attr_xmlel(AttrWithSpecialChars) -> #xmlel{name = <<"span">>, - attrs = [{<<"style">>, AttrWithSpecialChars}]}. + attrs = #{<<"style">> => AttrWithSpecialChars}}. diff --git a/big_tests/tests/tcp_listener_SUITE.erl b/big_tests/tests/tcp_listener_SUITE.erl index ae2ddb182b6..ac258897294 100644 --- a/big_tests/tests/tcp_listener_SUITE.erl +++ b/big_tests/tests/tcp_listener_SUITE.erl @@ -42,25 +42,14 @@ end_per_suite(_Config) -> teardown_meck(). setup_meck() -> - {Mod, Code} = dynamic_compile:from_string(tcp_listener_helper_code()), - rpc(mim(), code, load_binary, [Mod, "tcp_listener_helper.erl", Code]), + {Module, Binary, Filename} = code:get_object_code(tcp_listener_helper) , + rpc(mim(), code, load_binary, [Module, Filename, Binary]), ok = rpc(mim(), meck, new, [mongoose_tcp_listener, [passthrough, no_link]]), ok = rpc(mim(), tcp_listener_helper, setup_meck, []). teardown_meck() -> rpc(mim(), meck, unload, []). -tcp_listener_helper_code() -> - "-module(tcp_listener_helper).\n" - "-compile([export_all, nowarn_export_all]).\n" - "setup_meck() ->\n" - " meck:expect(mongoose_tcp_listener, read_connection_details, fun read_connection_details/2).\n\n" - "read_connection_details(Socket, Opts) ->\n" - " persistent_term:put(tcp_listener_helper_info, {Socket, self()}),\n" - " gen_tcp:close(Socket),\n" - " Result = meck:passthrough([Socket, Opts]),\n" - " persistent_term:put(tcp_listener_helper_result, Result),\n" - " Result.\n". %%-------------------------------------------------------------------- %% Test cases diff --git a/big_tests/tests/vcard_SUITE.erl b/big_tests/tests/vcard_SUITE.erl index 9b58715328a..0b6feadbfb8 100644 --- a/big_tests/tests/vcard_SUITE.erl +++ b/big_tests/tests/vcard_SUITE.erl @@ -483,9 +483,9 @@ search_rsm_pages(Config) -> Iq2 = append_to_query( Iq1, #xmlel{name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = - [#xmlel{name = "max", + [#xmlel{name = <<"max">>, children = [#xmlcdata{content = <<"1">>}] } @@ -507,13 +507,13 @@ search_rsm_pages(Config) -> Iq3 = append_to_query( Iq1, #xmlel{name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = - [#xmlel{name = "max", + [#xmlel{name = <<"max">>, children = [#xmlcdata{content = <<"1">>}] }, - #xmlel{name = "index", + #xmlel{name = <<"index">>, children = [#xmlcdata{content = <<"1">>}] } @@ -560,9 +560,9 @@ search_rsm_forward(Config) -> Iq2 = append_to_query( Iq1, #xmlel{name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = - [#xmlel{name = "max", + [#xmlel{name = <<"max">>, children = [#xmlcdata{content = <<"1">>}] } @@ -585,13 +585,13 @@ search_rsm_forward(Config) -> Iq3 = append_to_query( Iq1, #xmlel{name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = - [#xmlel{name = "max", + [#xmlel{name = <<"max">>, children = [#xmlcdata{content = <<"1">>}] }, - #xmlel{name = "after", + #xmlel{name = <<"after">>, children = [#xmlcdata{content = RSMLast1}] } @@ -626,13 +626,13 @@ search_rsm_forward(Config) -> Iq4 = append_to_query( Iq1, #xmlel{name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = - [#xmlel{name = "max", + [#xmlel{name = <<"max">>, children = [#xmlcdata{content = <<"1">>}] }, - #xmlel{name = "after", + #xmlel{name = <<"after">>, children = [#xmlcdata{content = RSMLast2}] } @@ -668,13 +668,13 @@ search_rsm_backward(Config) -> Iq2 = append_to_query( Iq1, #xmlel{name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = - [#xmlel{name = "max", + [#xmlel{name = <<"max">>, children = [#xmlcdata{content = <<"1">>}] }, - #xmlel{name = "before"} + #xmlel{name = <<"before">>} ]} ), @@ -694,13 +694,13 @@ search_rsm_backward(Config) -> Iq3 = append_to_query( Iq1, #xmlel{name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = - [#xmlel{name = "max", + [#xmlel{name = <<"max">>, children = [#xmlcdata{content = <<"1">>}] }, - #xmlel{name = "before", + #xmlel{name = <<"before">>, children = [#xmlcdata{content = RSMFirst1}] } @@ -735,13 +735,13 @@ search_rsm_backward(Config) -> Iq4 = append_to_query( Iq1, #xmlel{name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = - [#xmlel{name = "max", + [#xmlel{name = <<"max">>, children = [#xmlcdata{content = <<"1">>}] }, - #xmlel{name = "before", + #xmlel{name = <<"before">>, children = [#xmlcdata{content = RSMFirst2}] } @@ -777,9 +777,9 @@ search_rsm_count(Config) -> Iq2 = append_to_query( Iq1, #xmlel{name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = - [#xmlel{name = "max", + [#xmlel{name = <<"max">>, children = [#xmlcdata{content = <<"0">>}] } @@ -1234,11 +1234,9 @@ stanza_get_vcard_field_cdata(Stanza, FieldName) -> field_tuples([]) -> []; field_tuples([#xmlel{name = <<"field">>, - attrs=Attrs, + attrs = Attrs, children=_Children} = El| Rest]) -> - {<<"type">>, Type} = lists:keyfind(<<"type">>, 1, Attrs), - {<<"var">>, Var} = lists:keyfind(<<"var">>, 1, Attrs), - {<<"label">>, Label} = lists:keyfind(<<"label">>, 1, Attrs), + #{<<"type">> := Type, <<"var">> := Var, <<"label">> := Label} = Attrs, case ?EL_CD(El, <<"value">>) of undefined -> [{Type, Var, Label}|field_tuples(Rest)]; @@ -1257,9 +1255,9 @@ item_field_tuples(_, []) -> []; item_field_tuples(ReportedFieldTups, [#xmlel{name = <<"field">>, - attrs=Attrs, - children=_Children} = El| Rest]) -> - {<<"var">>, Var} = lists:keyfind(<<"var">>, 1, Attrs), + attrs = Attrs, + children = _Children} = El| Rest]) -> + Var = maps:get(<<"var">>, Attrs), {Type, Var, Label} = lists:keyfind(Var, 2, ReportedFieldTups), [{Type, Var, Label, ?EL_CD(El, <<"value">>)} | item_field_tuples(ReportedFieldTups, Rest)]; @@ -1350,8 +1348,7 @@ verify_tuples(Received, Expected) -> search_result_item_tuples(Stanza) -> Result = ?EL(Stanza, <<"query">>), XData = ?EL(Result, <<"x">>), - #xmlel{ attrs = _XAttrs, - children = XChildren } = XData, + #xmlel{ children = XChildren } = XData, Reported = ?EL(XData, <<"reported">>), ReportedFieldTups = field_tuples(Reported#xmlel.children), _ItemTups = item_tuples(ReportedFieldTups, XChildren). diff --git a/big_tests/tests/vcard_simple_SUITE.erl b/big_tests/tests/vcard_simple_SUITE.erl index 4ea297e73a5..e30ad27113a 100644 --- a/big_tests/tests/vcard_simple_SUITE.erl +++ b/big_tests/tests/vcard_simple_SUITE.erl @@ -307,11 +307,9 @@ stanza_get_vcard_field_cdata(Stanza, FieldName) -> field_tuples([]) -> []; field_tuples([#xmlel{name = <<"field">>, - attrs=Attrs, - children=_Children} = El| Rest]) -> - {<<"type">>,Type} = lists:keyfind(<<"type">>, 1, Attrs), - {<<"var">>,Var} = lists:keyfind(<<"var">>, 1, Attrs), - {<<"label">>,Label} = lists:keyfind(<<"label">>, 1, Attrs), + attrs = Attrs, + children = _Children} = El| Rest]) -> + #{<<"type">> := Type, <<"var">> := Var, <<"label">> := Label} = Attrs, case ?EL_CD(El, <<"value">>) of undefined -> [{Type, Var, Label}|field_tuples(Rest)]; @@ -330,9 +328,9 @@ item_field_tuples(_, []) -> []; item_field_tuples(ReportedFieldTups, [#xmlel{name = <<"field">>, - attrs=Attrs, - children=_Children} = El| Rest]) -> - {<<"var">>,Var} = lists:keyfind(<<"var">>, 1, Attrs), + attrs = Attrs, + children = _Children} = El| Rest]) -> + Var = maps:get(<<"var">>, Attrs), {Type, Var, Label} = lists:keyfind(Var, 2, ReportedFieldTups), [{Type, Var, Label, ?EL_CD(El, <<"value">>)} | item_field_tuples(ReportedFieldTups, Rest)]; @@ -410,8 +408,7 @@ list_unordered_key_match2(Keypos, [ExpctdTup|Rest], ActualTuples) -> search_result_item_tuples(Stanza) -> Result = ?EL(Stanza, <<"query">>), XData = ?EL(Result, <<"x">>), - #xmlel{ attrs = _XAttrs, - children = XChildren } = XData, + #xmlel{ children = XChildren } = XData, Reported = ?EL(XData, <<"reported">>), ReportedFieldTups = field_tuples(Reported#xmlel.children), _ItemTups = item_tuples(ReportedFieldTups, XChildren). diff --git a/rebar.config b/rebar.config index da8c3066d43..bd6a69e81ff 100644 --- a/rebar.config +++ b/rebar.config @@ -46,7 +46,7 @@ {deps, [ %%% Stateless parsers - {exml, "3.4.1", {pkg, hexml}}, + {exml, "4.0.0", {pkg, hexml}}, {jiffy, "1.1.2"}, {jid, "2.2.0", {pkg, mongoose_jid}}, {tomerl, "0.5.0"}, diff --git a/rebar.lock b/rebar.lock index 0e51baacdb4..f751cb410dd 100644 --- a/rebar.lock +++ b/rebar.lock @@ -26,7 +26,7 @@ {<<"erl_csv">>,{pkg,<<"erl_csv">>,<<"0.3.3">>},0}, {<<"erlang_doctor">>,{pkg,<<"erlang_doctor">>,<<"0.2.7">>},0}, {<<"erlcloud">>,{pkg,<<"erlcloud">>,<<"3.8.1">>},0}, - {<<"exml">>,{pkg,<<"hexml">>,<<"3.4.1">>},0}, + {<<"exml">>,{pkg,<<"hexml">>,<<"4.0.0">>},0}, {<<"exometer_core">>, {git,"https://github.com/esl/exometer_core.git", {ref,"123daa053a4abb3ff4bdbf52f08344da535294e9"}}, @@ -142,7 +142,7 @@ {<<"erl_csv">>, <<"94FBA776D493FE0DA76786D694CC2A788F14C864766DBB04C1786272515898C4">>}, {<<"erlang_doctor">>, <<"38DCCF531B0DCF01B327EF437C7422EA3123457CF664C75BA8219D6022A7DA4B">>}, {<<"erlcloud">>, <<"134973B88EE93E087A5D6918FF826D247782B15CF5DF8A38DDE00DE905975596">>}, - {<<"exml">>, <<"9581FE6512D9772C61BBE611CD4A8E5BB90B4D4481275325EC520F7A931A9393">>}, + {<<"exml">>, <<"54C1AAD5BD290EC31C19CE4A5D449C7E3236107AA2D3610FC04FC963DC8EAF13">>}, {<<"fast_pbkdf2">>, <<"6045138C4C209FC8222A0B18B2CB1D7BD7407EF4ADAD0F14C5E0F7F4726E3E41">>}, {<<"fast_scram">>, <<"70724F584A118DA147A51EE38DEE56203F217D58AD61E0BB2C2EF834C16B35B8">>}, {<<"fast_tls">>, <<"44356B256AFAD4399C2FC5059A3066669DAFD8BD4E4E796C9C1CF8910DDD265E">>}, @@ -213,7 +213,7 @@ {<<"erl_csv">>, <<"B1B4B5F6578B2AFC307E8CBF67277AC8E3D721FE5E6B5A4D53BA49215C9600F3">>}, {<<"erlang_doctor">>, <<"5895F16E04666843895479D60624751330F87D8296411E03EC405F42F697796D">>}, {<<"erlcloud">>, <<"DCBE1D49A3E01381A39F90E1119F2AC8632AEB8A51ADB3CAD313C299F5E8B341">>}, - {<<"exml">>, <<"D8E7894E2544402B4986EEB2443C15B51B14F686266F091DBF2777D1D99A2FA2">>}, + {<<"exml">>, <<"08CC97527C708D57A03F467049AC260B5951BD67906AA154BE56B5D8BDD3238C">>}, {<<"fast_pbkdf2">>, <<"BC3B5A3CAB47AD114FF8BB815FEDE62A6187ACD14D8B37412F2AF8236A089CEF">>}, {<<"fast_scram">>, <<"771D034341599CFC6A6C5E56CF924B68D2C7478088CAF17419E3147B66914667">>}, {<<"fast_tls">>, <<"E65779AEFB7AB15C4755230FEF8077E687D20CC5A3984A5974F9F657E8E2485B">>}, diff --git a/src/adhoc.erl b/src/adhoc.erl index 11a61de1414..191f691049a 100644 --- a/src/adhoc.erl +++ b/src/adhoc.erl @@ -109,16 +109,16 @@ produce_response(#adhoc_response{lang = _Lang, ActionsEls = maybe_actions_element(Actions, DefaultAction), NotesEls = lists:map(fun note_to_xmlel/1, Notes), #xmlel{name = <<"command">>, - attrs = [{<<"xmlns">>, ?NS_COMMANDS}, - {<<"sessionid">>, SessionID}, - {<<"node">>, Node}, - {<<"status">>, atom_to_binary(Status)}], + attrs = #{<<"xmlns">> => ?NS_COMMANDS, + <<"sessionid">> => SessionID, + <<"node">> => Node, + <<"status">> => atom_to_binary(Status)}, children = ActionsEls ++ NotesEls ++ Elements}. -spec ensure_correct_session_id(binary()) -> binary(). ensure_correct_session_id(SessionID) when is_binary(SessionID), SessionID /= <<>> -> SessionID; -ensure_correct_session_id(_) -> +ensure_correct_session_id(_) -> USec = os:system_time(microsecond), TS = calendar:system_time_to_rfc3339(USec, [{offset, "Z"}, {unit, microsecond}]), list_to_binary(TS). @@ -139,7 +139,7 @@ maybe_actions_element(Actions, DefaultAction) -> AllActions = ensure_default_action_present(Actions, DefaultAction), [#xmlel{ name = <<"actions">>, - attrs = [{<<"execute">>, DefaultAction}], + attrs = #{<<"execute">> => DefaultAction}, children = [#xmlel{name = Action} || Action <- AllActions] }]. @@ -154,6 +154,6 @@ ensure_default_action_present(Actions, DefaultAction) -> note_to_xmlel({Type, Text}) -> #xmlel{ name = <<"note">>, - attrs = [{<<"type">>, Type}], + attrs = #{<<"type">> => Type}, children = [#xmlcdata{content = Text}] }. diff --git a/src/amp.erl b/src/amp.erl index 998d318575b..d493ef9549f 100644 --- a/src/amp.erl +++ b/src/amp.erl @@ -61,13 +61,13 @@ make_response(Rule, User, Packet) -> OriginalRecipient = exml_query:attr(Packet, <<"to">>), Amp = #xmlel{name = <<"amp">>, - attrs = [{<<"xmlns">>, ?NS_AMP}, - {<<"status">>, to_bin_(Rule#amp_rule.action)}, - {<<"to">>, OriginalRecipient}, - {<<"from">>, OriginalSender}], + attrs = #{<<"xmlns">> => ?NS_AMP, + <<"status">> => to_bin_(Rule#amp_rule.action), + <<"to">> => OriginalRecipient, + <<"from">> => OriginalSender}, children = [rule_to_xmlel(Rule)]}, #xmlel{name = <<"message">>, - attrs = [{<<"id">>, OriginalId}], + attrs = #{<<"id">> => OriginalId}, children = [Amp]}. @@ -77,12 +77,12 @@ make_error_response([E|_] = Errors, [_|_] = Rules, User, Packet) -> OriginalId = exml_query:attr(Packet, <<"id">>, <<"original-id-missing">>), Error = make_error_el(Errors, Rules), Amp = #xmlel{name = <<"amp">>, - attrs = [{<<"xmlns">>, ?NS_AMP} | - error_amp_attrs(E, User, Packet)], + attrs = maps:put(<<"xmlns">>, ?NS_AMP, + error_amp_attrs(E, User, Packet)), children = [rule_to_xmlel(R) || R <- Rules]}, #xmlel{name = <<"message">>, - attrs = [{<<"id">>, OriginalId}, - {<<"type">>, <<"error">>}], + attrs = #{<<"id">> => OriginalId, + <<"type">> => <<"error">>}, children = [Error, Amp]}; make_error_response(Errors, Rules, User, Packet) -> ?LOG_ERROR(#{what => make_error_response_failed, @@ -95,10 +95,10 @@ make_error_response(Errors, Rules, User, Packet) -> error_amp_attrs('undefined-condition', User, Packet) -> OriginalSender = jid:to_binary(User), OriginalRecipient = exml_query:attr(Packet, <<"to">>), - [{<<"status">>, <<"error">>}, - {<<"to">>, OriginalRecipient}, - {<<"from">>, OriginalSender}]; -error_amp_attrs(_, _, _) -> []. + #{<<"status">> => <<"error">>, + <<"to">> => OriginalRecipient, + <<"from">> => OriginalSender}; +error_amp_attrs(_, _, _) -> #{}. %% The lists are guaranteed to be non-empty and of equal @@ -106,26 +106,26 @@ error_amp_attrs(_, _, _) -> []. -spec make_error_el([amp_error()], [amp_any_rule()]) -> #xmlel{}. make_error_el(Errors, Rules) -> ErrorMarker = #xmlel{name = error_marker_name(hd(Errors)), - attrs = [{<<"xmlns">>, ?NS_STANZAS}]}, + attrs = #{<<"xmlns">> => ?NS_STANZAS}}, RuleContainer = #xmlel{name = rule_container_name(hd(Errors)), - attrs = [{<<"xmlns">>, ?NS_AMP}], + attrs = #{<<"xmlns">> => ?NS_AMP}, children = [ rule_to_xmlel(R) || R <- Rules ]}, #xmlel{name = <<"error">>, - attrs = [{<<"type">>, <<"modify">>}, - {<<"code">>, error_code(hd(Errors))}], + attrs = #{<<"type">> => <<"modify">>, + <<"code">> => error_code(hd(Errors))}, children = [ErrorMarker, RuleContainer]}. -spec rule_to_xmlel(amp_any_rule()) -> #xmlel{}. rule_to_xmlel(#amp_rule{condition=C, value=V, action=A}) -> #xmlel{name = <<"rule">>, - attrs = [{<<"condition">>, to_bin_(C)}, - {<<"value">>, to_bin_(V)}, - {<<"action">>, to_bin_(A)}]}; + attrs = #{<<"condition">> => to_bin_(C), + <<"value">> => to_bin_(V), + <<"action">> => to_bin_(A)}}; rule_to_xmlel(#amp_invalid_rule{condition=C, value=V, action=A}) -> #xmlel{name = <<"rule">>, - attrs = [{<<"condition">>, C}, - {<<"value">>, V}, - {<<"action">>, A}]}. + attrs = #{<<"condition">> => C, + <<"value">> => V, + <<"action">> => A}}. -spec strip_amp_el(#xmlel{}) -> #xmlel{}. strip_amp_el(#xmlel{children = Children} = Elem) -> @@ -167,7 +167,7 @@ parse_rules(Stanza) -> -spec parse_rule(#xmlel{}) -> amp_rule() | amp_invalid_rule(). parse_rule(#xmlel{attrs = Attrs}) -> - GetF = fun(Value) -> proplists:get_value(Value, Attrs, <<"attribute-missing">>) end, + GetF = fun(Value) -> maps:get(Value, Attrs, <<"attribute-missing">>) end, {C, V, A} = {GetF(<<"condition">>), GetF(<<"value">>), GetF(<<"action">>)}, diff --git a/src/c2s/mongoose_c2s.erl b/src/c2s/mongoose_c2s.erl index 7cce8eaad23..5395d6cf026 100644 --- a/src/c2s/mongoose_c2s.erl +++ b/src/c2s/mongoose_c2s.erl @@ -297,7 +297,7 @@ elem_size(El) -> exml:xml_size(patch_element(El)). patch_element(El = #xmlstreamstart{attrs = Attrs}) -> - Attrs2 = [{Name, patch_attr_value(Value)} || {Name, Value} <- Attrs], + Attrs2 = #{Name => patch_attr_value(Value) || Name := Value <- Attrs}, El#xmlstreamstart{attrs = Attrs2}; patch_element(El) -> El. diff --git a/src/c2s/mongoose_c2s_stanzas.erl b/src/c2s/mongoose_c2s_stanzas.erl index 6b13d89c923..aa1f8f9b91e 100644 --- a/src/c2s/mongoose_c2s_stanzas.erl +++ b/src/c2s/mongoose_c2s_stanzas.erl @@ -22,14 +22,16 @@ stream_header(StateData) -> Lang = mongoose_c2s:get_lang(StateData), LServer = mongoose_c2s:get_lserver(StateData), StreamId = mongoose_c2s:get_stream_id(StateData), - MaybeFrom = [ {<<"to">>, jid:to_binary(Jid)} - || Jid <- [mongoose_c2s:get_jid(StateData)], Jid =/= undefined], - Attrs = [{<<"xmlns">>, ?NS_CLIENT}, - {<<"xmlns:stream">>, <<"http://etherx.jabber.org/streams">>}, - {<<"id">>, StreamId}, - {<<"from">>, LServer}, - {<<"version">>, ?XMPP_VERSION}, - {<<"xml:lang">>, Lang} | MaybeFrom ], + MaybeFrom = case mongoose_c2s:get_jid(StateData) of + undefined -> #{}; + Jid -> #{<<"to">> => jid:to_binary(Jid)} + end, + Attrs = MaybeFrom#{<<"xmlns">> => ?NS_CLIENT, + <<"xmlns:stream">> => <<"http://etherx.jabber.org/streams">>, + <<"id">> => StreamId, + <<"from">> => LServer, + <<"version">> => ?XMPP_VERSION, + <<"xml:lang">> => Lang}, #xmlstreamstart{name = <<"stream:stream">>, attrs = Attrs}. -spec stream_features([exml:element() | exml:cdata()]) -> exml:element(). @@ -73,7 +75,7 @@ maybe_sasl_mechanisms(StateData) -> [] -> []; Mechanisms -> [#xmlel{name = <<"mechanisms">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], + attrs = #{<<"xmlns">> => ?NS_SASL}, children = [ mechanism(M) || M <- Mechanisms ]}] end. @@ -84,32 +86,32 @@ mechanism(M) -> -spec starttls_stanza(required | optional) -> exml:element(). starttls_stanza(TLSRequired) when TLSRequired =:= required; TLSRequired =:= optional -> #xmlel{name = <<"starttls">>, - attrs = [{<<"xmlns">>, ?NS_TLS}], + attrs = #{<<"xmlns">> => ?NS_TLS}, children = [ #xmlel{name = <<"required">>} || TLSRequired =:= required ]}. -spec tls_proceed() -> exml:element(). tls_proceed() -> #xmlel{name = <<"proceed">>, - attrs = [{<<"xmlns">>, ?NS_TLS}]}. + attrs = #{<<"xmlns">> => ?NS_TLS}}. -spec tls_failure() -> exml:element(). tls_failure() -> #xmlel{name = <<"failure">>, - attrs = [{<<"xmlns">>, ?NS_TLS}]}. + attrs = #{<<"xmlns">> => ?NS_TLS}}. -spec stream_features_after_auth(mongoose_c2s:data()) -> exml:element(). stream_features_after_auth(StateData) -> case mongoose_c2s:get_listener_opts(StateData) of #{backwards_compatible_session := false} -> Features = [#xmlel{name = <<"bind">>, - attrs = [{<<"xmlns">>, ?NS_BIND}]} + attrs = #{<<"xmlns">> => ?NS_BIND}} | hook_enabled_features(StateData)], stream_features(Features); #{backwards_compatible_session := true} -> Features = [#xmlel{name = <<"session">>, - attrs = [{<<"xmlns">>, ?NS_SESSION}]}, + attrs = #{<<"xmlns">> => ?NS_SESSION}}, #xmlel{name = <<"bind">>, - attrs = [{<<"xmlns">>, ?NS_BIND}]} + attrs = #{<<"xmlns">> => ?NS_BIND}} | hook_enabled_features(StateData)], stream_features(Features) end. @@ -128,7 +130,7 @@ sasl_success_stanza(ServerOut) -> _ -> [#xmlcdata{content = base64:encode(ServerOut)}] end, #xmlel{name = <<"success">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], + attrs = #{<<"xmlns">> => ?NS_SASL}, children = C}. -spec sasl_failure_stanza(binary() | {binary(), iodata() | undefined}) -> exml:element(). @@ -136,7 +138,7 @@ sasl_failure_stanza(Error) when is_binary(Error) -> sasl_failure_stanza({Error, undefined}); sasl_failure_stanza({Error, Text}) -> #xmlel{name = <<"failure">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], + attrs = #{<<"xmlns">> => ?NS_SASL}, children = [#xmlel{name = Error} | maybe_text_tag(Text)]}. maybe_text_tag(undefined) -> []; @@ -147,7 +149,7 @@ maybe_text_tag(Text) -> -spec sasl_challenge_stanza(binary()) -> exml:element(). sasl_challenge_stanza(ServerOut) -> #xmlel{name = <<"challenge">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], + attrs = #{<<"xmlns">> => ?NS_SASL}, children = [#xmlcdata{content = base64:encode(ServerOut)}]}. -spec successful_resource_binding(jlib:iq(), jid:jid()) -> exml:element(). @@ -156,7 +158,7 @@ successful_resource_binding(IQ, Jid) -> children = [#xmlcdata{content = jid:to_binary(Jid)}]}, Res = IQ#iq{type = result, sub_el = [#xmlel{name = <<"bind">>, - attrs = [{<<"xmlns">>, ?NS_BIND}], + attrs = #{<<"xmlns">> => ?NS_BIND}, children = [JIDEl]}]}, jlib:iq_to_xml(Res). @@ -164,5 +166,5 @@ successful_resource_binding(IQ, Jid) -> successful_session_establishment(IQ) -> Res = IQ#iq{type = result, sub_el = [#xmlel{name = <<"session">>, - attrs = [{<<"xmlns">>, ?NS_SESSION}]}]}, + attrs = #{<<"xmlns">> => ?NS_SESSION}}]}, jlib:iq_to_xml(Res). diff --git a/src/ejabberd.erl b/src/ejabberd.erl index 58f65b71c25..80db47a10b7 100644 --- a/src/ejabberd.erl +++ b/src/ejabberd.erl @@ -33,9 +33,9 @@ -type xml_stream_item() :: 'closed' | 'timeout' | {'xmlstreamelement', exml:element()} - | {'xmlstreamend', _} - | {'xmlstreamerror', _} - | {'xmlstreamstart', Name :: binary(), Attrs :: [exml:attr()]}. + | exml_stream:start() + | exml_stream:stop() + | jlib:xmlstreamerror(). -export_type([lang/0, xml_stream_item/0]). diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl index 80e73b3ebc1..47b3470f9c1 100644 --- a/src/ejabberd_s2s_in.erl +++ b/src/ejabberd_s2s_in.erl @@ -56,6 +56,7 @@ -include("mongoose.hrl"). -include("jlib.hrl"). +-include_lib("exml/include/exml_stream.hrl"). -record(state, {socket :: mongoose_transport:socket_data(), streamid :: ejabberd_s2s:stream_id(), @@ -175,9 +176,9 @@ init([Socket, #{shaper := Shaper, tls := TLSOpts}]) -> %%---------------------------------------------------------------------- -spec wait_for_stream(ejabberd:xml_stream_item(), state()) -> fsm_return(). -wait_for_stream({xmlstreamstart, _Name, Attrs} = Event, StateData) -> - case maps:from_list(Attrs) of - AttrMap = #{<<"xmlns">> := <<"jabber:server">>, <<"to">> := Server} -> +wait_for_stream(#xmlstreamstart{attrs = Attrs} = Event, StateData) -> + case Attrs of + #{<<"xmlns">> := <<"jabber:server">>, <<"to">> := Server} -> case StateData#state.server of undefined -> case mongoose_domain_api:get_host_type(Server) of @@ -187,14 +188,14 @@ wait_for_stream({xmlstreamstart, _Name, Attrs} = Event, StateData) -> {ok, HostType} -> UseTLS = mongoose_config:get_opt([{s2s, HostType}, use_starttls]), {StartTLS, TLSRequired, TLSCertVerify} = get_tls_params(UseTLS), - start_stream(AttrMap, StateData#state{server = Server, + start_stream(Attrs, StateData#state{server = Server, host_type = HostType, tls = StartTLS, tls_required = TLSRequired, tls_cert_verify = TLSCertVerify}) end; Server -> - start_stream(AttrMap, StateData); + start_stream(Attrs, StateData); _Other -> Msg = <<"The 'to' attribute differs from the originally provided one">>, Info = #{location => ?LOCATION, last_event => Event, @@ -209,7 +210,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs} = Event, StateData) -> Info = #{location => ?LOCATION, last_event => Event}, stream_start_error(StateData, Info, mongoose_xmpp_errors:invalid_namespace()) end; -wait_for_stream({xmlstreamerror, _} = Event, StateData) -> +wait_for_stream(#xmlstreamerror{} = Event, StateData) -> Info = #{location => ?LOCATION, last_event => Event, reason => s2s_in_wait_for_stream_error}, stream_start_error(StateData, Info, mongoose_xmpp_errors:xml_not_well_formed()); @@ -286,7 +287,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> TLSSocket = mongoose_transport:wait_for_tls_handshake( StateData#state.socket, TLSOpts, #xmlel{name = <<"proceed">>, - attrs = [{<<"xmlns">>, ?NS_TLS}]}), + attrs = #{<<"xmlns">> => ?NS_TLS}}), {next_state, wait_for_stream, StateData#state{socket = TLSSocket, streamid = new_id(), @@ -305,7 +306,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> _ -> send_element(StateData, #xmlel{name = <<"failure">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], + attrs = #{<<"xmlns">> => ?NS_SASL}, children = [#xmlel{name = <<"invalid-mechanism">>}]}), ?LOG_WARNING(#{what => s2s_in_invalid_mechanism}), {stop, normal, StateData} @@ -313,11 +314,11 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) -> _ -> stream_established({xmlstreamelement, El}, StateData) end; -wait_for_feature_request({xmlstreamend, _Name}, StateData) -> +wait_for_feature_request(#xmlstreamend{}, StateData) -> send_text(StateData, ?STREAM_TRAILER), ?LOG_WARNING(#{what => s2s_in_got_stream_end_before_feature_request}), {stop, normal, StateData}; -wait_for_feature_request({xmlstreamerror, _}, StateData) -> +wait_for_feature_request(#xmlstreamerror{}, StateData) -> send_element(StateData, mongoose_xmpp_errors:xml_not_well_formed()), send_text(StateData, ?STREAM_TRAILER), ?LOG_WARNING(#{what => s2s_in_got_stream_error_before_feature_request}), @@ -383,10 +384,10 @@ stream_established({xmlstreamelement, El}, StateData) -> end; stream_established({validity_from_s2s_out, IsValid, FromTo}, StateData) -> handle_validity_from_s2s_out(IsValid, FromTo, StateData); -stream_established({xmlstreamend, _Name}, StateData) -> +stream_established(#xmlstreamend{}, StateData) -> send_text(StateData, ?STREAM_TRAILER), {stop, normal, StateData}; -stream_established({xmlstreamerror, _}, StateData) -> +stream_established(#xmlstreamerror{}, StateData) -> send_element(StateData, mongoose_xmpp_errors:xml_not_well_formed()), send_text(StateData, ?STREAM_TRAILER), ?LOG_WARNING(#{what => s2s_in_stream_error, state_name => stream_established}), @@ -593,7 +594,7 @@ verify_cert_and_get_sasl(Socket, TLSCertVerify) -> case mongoose_transport:get_peer_certificate(Socket) of {ok, _} -> [#xmlel{name = <<"mechanisms">>, - attrs = [{<<"xmlns">>, ?NS_SASL}], + attrs = #{<<"xmlns">> => ?NS_SASL}, children = [#xmlel{name = <<"mechanism">>, children = [#xmlcdata{content = <<"EXTERNAL">>}]}]}]; {bad_cert, CertVerifyRes} -> @@ -623,7 +624,7 @@ check_auth_domain(_, _) -> handle_auth_res(true, AuthDomain, StateData) -> send_element(StateData, #xmlel{name = <<"success">>, - attrs = [{<<"xmlns">>, ?NS_SASL}]}), + attrs = #{<<"xmlns">> => ?NS_SASL}}), ?LOG_DEBUG(#{what => s2s_auth_success, text => <<"Accepted s2s authentication">>, socket => StateData#state.socket, auth_domain => AuthDomain}), @@ -635,7 +636,7 @@ handle_auth_res(true, AuthDomain, StateData) -> handle_auth_res(_, _, StateData) -> send_element(StateData, #xmlel{name = <<"failure">>, - attrs = [{<<"xmlns">>, ?NS_SASL}]}), + attrs = #{<<"xmlns">> => ?NS_SASL}}), send_text(StateData, ?STREAM_TRAILER), ?LOG_WARNING(#{what => s2s_in_auth_failed}), {stop, normal, StateData}. @@ -656,10 +657,10 @@ get_tls_xmlel(#state{tls_enabled = true}) -> []; get_tls_xmlel(#state{tls_enabled = false, tls_required = false}) -> [#xmlel{name = <<"starttls">>, - attrs = [{<<"xmlns">>, ?NS_TLS}]}]; + attrs = #{<<"xmlns">> => ?NS_TLS}}]; get_tls_xmlel(#state{tls_enabled = false, tls_required = true}) -> [#xmlel{name = <<"starttls">>, - attrs = [{<<"xmlns">>, ?NS_TLS}], + attrs = #{<<"xmlns">> => ?NS_TLS}, children = [#xmlel{name = <<"required">>}]}]. -spec is_local_host_known(ejabberd_s2s:fromto()) -> boolean(). diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index ae6229d5028..26faf3a6c56 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -67,6 +67,7 @@ -include("mongoose.hrl"). -include("jlib.hrl"). +-include_lib("exml/include/exml_stream.hrl"). -record(state, {socket, streamid :: ejabberd_s2s:stream_id() | undefined, @@ -312,13 +313,12 @@ open_socket2(HostType, Type, Addr, Port) -> %%---------------------------------------------------------------------- -spec wait_for_stream(ejabberd:xml_stream_item(), state()) -> fsm_return(). -wait_for_stream({xmlstreamstart, Name, Attrs}, StateData0) -> - StreamStart = #xmlel{name = Name, attrs = Attrs}, - RemoteStreamID = exml_query:attr(StreamStart, <<"id">>, <<>>), +wait_for_stream(#xmlstreamstart{attrs = Attrs}, StateData0) -> + RemoteStreamID = maps:get(<<"id">>, Attrs, <<>>), StateData = StateData0#state{remote_streamid = RemoteStreamID}, - case {exml_query:attr(StreamStart, <<"xmlns">>, <<>>), - exml_query:attr(StreamStart, <<"xmlns:db">>, <<>>), - exml_query:attr(StreamStart, <<"version">>, <<>>) =:= <<"1.0">>} of + case {maps:get(<<"xmlns">>, Attrs, <<>>), + maps:get(<<"xmlns:db">>, Attrs, <<>>), + maps:get(<<"version">>, Attrs, <<>>) =:= <<"1.0">>} of {<<"jabber:server">>, <<"jabber:server:dialback">>, false} -> send_dialback_request(StateData); {<<"jabber:server">>, <<"jabber:server:dialback">>, true} when @@ -341,11 +341,11 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData0) -> myname => StateData#state.myname, server => StateData#state.server}), {stop, normal, StateData} end; -wait_for_stream({xmlstreamerror, _}, StateData) -> +wait_for_stream(#xmlstreamerror{}, StateData) -> send_element(StateData, mongoose_xmpp_errors:xml_not_well_formed()), send_text(StateData, ?STREAM_TRAILER), ?CLOSE_GENERIC(wait_for_stream, xmlstreamerror, StateData); -wait_for_stream({xmlstreamend, _Name}, StateData) -> +wait_for_stream(#xmlstreamend{}, StateData) -> ?CLOSE_GENERIC(wait_for_stream, xmlstreamend, StateData); wait_for_stream(timeout, StateData) -> ?CLOSE_GENERIC(wait_for_stream, timeout, StateData); @@ -393,9 +393,9 @@ wait_for_validation({xmlstreamelement, El}, StateData = #state{from_to = FromTo} false -> {next_state, wait_for_validation, StateData, ?FSMTIMEOUT*3} end; -wait_for_validation({xmlstreamend, _Name}, StateData) -> +wait_for_validation(#xmlstreamend{}, StateData) -> ?CLOSE_GENERIC(wait_for_validation, xmlstreamend, StateData); -wait_for_validation({xmlstreamerror, _}, StateData) -> +wait_for_validation(#xmlstreamerror{}, StateData) -> send_element(StateData, mongoose_xmpp_errors:xml_not_well_formed()), send_text(StateData, ?STREAM_TRAILER), ?CLOSE_GENERIC(wait_for_validation, xmlstreamerror, StateData); @@ -440,9 +440,9 @@ wait_for_features({xmlstreamelement, El}, StateData) -> send_text(StateData, ?STREAM_TRAILER), ?CLOSE_GENERIC(wait_for_features, bad_format, El, StateData) end; -wait_for_features({xmlstreamend, _Name}, StateData) -> +wait_for_features(#xmlstreamend{}, StateData) -> ?CLOSE_GENERIC(wait_for_features, xmlstreamend, StateData); -wait_for_features({xmlstreamerror, _}, StateData) -> +wait_for_features(#xmlstreamerror{}, StateData) -> send_element(StateData, mongoose_xmpp_errors:xml_not_well_formed()), send_text(StateData, ?STREAM_TRAILER), ?CLOSE_GENERIC(wait_for_features, xmlstreamerror, StateData); @@ -493,9 +493,9 @@ wait_for_auth_result({xmlstreamelement, El}, StateData) -> send_text(StateData, ?STREAM_TRAILER), ?CLOSE_GENERIC(wait_for_auth_result, bad_format, El, StateData) end; -wait_for_auth_result({xmlstreamend, _Name}, StateData) -> +wait_for_auth_result(#xmlstreamend{}, StateData) -> ?CLOSE_GENERIC(wait_for_auth_result, xmlstreamend, StateData); -wait_for_auth_result({xmlstreamerror, _}, StateData) -> +wait_for_auth_result(#xmlstreamerror{}, StateData) -> send_element(StateData, mongoose_xmpp_errors:xml_not_well_formed()), send_text(StateData, ?STREAM_TRAILER), ?CLOSE_GENERIC(wait_for_auth_result, xmlstreamerror, StateData); @@ -531,9 +531,9 @@ wait_for_starttls_proceed({xmlstreamelement, El}, StateData) -> _ -> ?CLOSE_GENERIC(wait_for_auth_result, bad_format, El, StateData) end; -wait_for_starttls_proceed({xmlstreamend, _Name}, StateData) -> +wait_for_starttls_proceed(#xmlstreamend{}, StateData) -> ?CLOSE_GENERIC(wait_for_starttls_proceed, xmlstreamend, StateData); -wait_for_starttls_proceed({xmlstreamerror, _}, StateData) -> +wait_for_starttls_proceed(#xmlstreamerror{}, StateData) -> send_element(StateData, mongoose_xmpp_errors:xml_not_well_formed()), send_text(StateData, ?STREAM_TRAILER), ?CLOSE_GENERIC(wait_for_starttls_proceed, xmlstreamerror, StateData); @@ -546,9 +546,9 @@ wait_for_starttls_proceed(closed, StateData) -> -spec reopen_socket(ejabberd:xml_stream_item(), state()) -> fsm_return(). reopen_socket({xmlstreamelement, _El}, StateData) -> {next_state, reopen_socket, StateData, ?FSMTIMEOUT}; -reopen_socket({xmlstreamend, _Name}, StateData) -> +reopen_socket(#xmlstreamend{}, StateData) -> {next_state, reopen_socket, StateData, ?FSMTIMEOUT}; -reopen_socket({xmlstreamerror, _}, StateData) -> +reopen_socket(#xmlstreamerror{}, StateData) -> {next_state, reopen_socket, StateData, ?FSMTIMEOUT}; reopen_socket(timeout, StateData) -> ?CLOSE_GENERIC(reopen_socket, timeout, StateData); @@ -583,9 +583,9 @@ stream_established({xmlstreamelement, El}, StateData = #state{from_to = FromTo}) ok end, {next_state, stream_established, StateData}; -stream_established({xmlstreamend, _Name}, StateData) -> +stream_established(#xmlstreamend{}, StateData) -> ?CLOSE_GENERIC(stream_established, xmlstreamend, StateData); -stream_established({xmlstreamerror, _}, StateData) -> +stream_established(#xmlstreamerror{}, StateData) -> send_element(StateData, mongoose_xmpp_errors:xml_not_well_formed()), send_text(StateData, ?STREAM_TRAILER), ?CLOSE_GENERIC(stream_established, xmlstreamerror, StateData); @@ -1123,8 +1123,8 @@ handle_parsed_features({false, false, _, StateData = #state{authenticated = true handle_parsed_features({true, _, _, StateData = #state{try_auth = true, is_registered = true}}) -> send_element(StateData, #xmlel{name = <<"auth">>, - attrs = [{<<"xmlns">>, ?NS_SASL}, - {<<"mechanism">>, <<"EXTERNAL">>}], + attrs = #{<<"xmlns">> => ?NS_SASL, + <<"mechanism">> => <<"EXTERNAL">>}, children = [#xmlcdata{content = base64:encode( StateData#state.myname)}]}), @@ -1133,7 +1133,7 @@ handle_parsed_features({true, _, _, StateData = #state{try_auth = true, is_regis handle_parsed_features({_, true, _, StateData = #state{tls = true, tls_enabled = false}}) -> send_element(StateData, #xmlel{name = <<"starttls">>, - attrs = [{<<"xmlns">>, ?NS_TLS}]}), + attrs = #{<<"xmlns">> => ?NS_TLS}}), {next_state, wait_for_starttls_proceed, StateData, ?FSMTIMEOUT}; handle_parsed_features({_, _, true, StateData = #state{tls = false}}) -> diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl index 6f297bde958..059146e91c2 100644 --- a/src/ejabberd_service.erl +++ b/src/ejabberd_service.erl @@ -60,6 +60,8 @@ -include("mongoose.hrl"). -include("jlib.hrl"). -include("external_component.hrl"). +-include_lib("exml/include/exml_stream.hrl"). + -type conflict_behaviour() :: disconnect | kick_old. @@ -201,17 +203,16 @@ init([Socket, Opts]) -> %%---------------------------------------------------------------------- -spec wait_for_stream(ejabberd:xml_stream_item(), state()) -> fsm_return(). -wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> - StreamStart = #xmlel{name = Name, attrs = Attrs}, - case exml_query:attr(StreamStart, <<"xmlns">>) of +wait_for_stream(#xmlstreamstart{attrs = Attrs}, StateData) -> + case maps:get(<<"xmlns">>, Attrs, undefined) of <<"jabber:component:accept">> -> %% Note: XEP-0114 requires to check that destination is a Jabber %% component served by this Jabber server. %% However several transports don't respect that, %% so ejabberd doesn't check 'to' attribute (EJAB-717) - To = exml_query:attr(StreamStart, <<"to">>, <<>>), + To = maps:get(<<"to">>, Attrs, <<>>), Header = io_lib:format(?STREAM_HEADER, [StateData#state.streamid, To]), - IsSubdomain = case exml_query:attr(StreamStart, <<"is_subdomain">>) of + IsSubdomain = case maps:get(<<"is_subdomain">>, Attrs, undefined) of <<"true">> -> true; _ -> false end, @@ -223,7 +224,7 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) -> send_text(StateData, ?INVALID_HEADER_ERR), {stop, normal, StateData} end; -wait_for_stream({xmlstreamerror, _}, StateData) -> +wait_for_stream(#xmlstreamerror{}, StateData) -> Header = io_lib:format(?STREAM_HEADER, [<<"none">>, ?MYNAME]), send_text(StateData, iolist_to_binary(Header)), @@ -251,9 +252,9 @@ wait_for_handshake({xmlstreamelement, El}, StateData) -> _ -> {next_state, wait_for_handshake, StateData} end; -wait_for_handshake({xmlstreamend, _Name}, StateData) -> +wait_for_handshake(#xmlstreamend{}, StateData) -> {stop, normal, StateData}; -wait_for_handshake({xmlstreamerror, _}, StateData) -> +wait_for_handshake(#xmlstreamerror{}, StateData) -> send_element(StateData, mongoose_xmpp_errors:xml_not_well_formed()), send_text(StateData, ?STREAM_TRAILER), {stop, normal, StateData}; @@ -305,10 +306,10 @@ stream_established({xmlstreamelement, El}, StateData) -> error end, {next_state, stream_established, StateData}; -stream_established({xmlstreamend, _Name}, StateData) -> +stream_established(#xmlstreamend{}, StateData) -> % TODO ?? {stop, normal, StateData}; -stream_established({xmlstreamerror, _}, StateData) -> +stream_established(#xmlstreamerror{}, StateData) -> send_element(StateData, mongoose_xmpp_errors:xml_not_well_formed()), send_text(StateData, ?STREAM_TRAILER), {stop, normal, StateData}; diff --git a/src/event_pusher/mod_event_pusher_push_plugin_defaults.erl b/src/event_pusher/mod_event_pusher_push_plugin_defaults.erl index 2f66f4d8d23..5b5b0ace4d1 100644 --- a/src/event_pusher/mod_event_pusher_push_plugin_defaults.erl +++ b/src/event_pusher/mod_event_pusher_push_plugin_defaults.erl @@ -182,11 +182,11 @@ handle_publish_response(HostType, Recipient, PubsubJID, Node, #iq{type = error, jlib:iq(). push_notification_iq(Node, Form, PushPayload) -> #iq{type = set, sub_el = [ - #xmlel{name = <<"pubsub">>, attrs = [{<<"xmlns">>, ?NS_PUBSUB}], children = [ - #xmlel{name = <<"publish">>, attrs = [{<<"node">>, Node}], children = [ + #xmlel{name = <<"pubsub">>, attrs = #{<<"xmlns">> => ?NS_PUBSUB}, children = [ + #xmlel{name = <<"publish">>, attrs = #{<<"node">> => Node}, children = [ #xmlel{name = <<"item">>, children = [ #xmlel{name = <<"notification">>, - attrs = [{<<"xmlns">>, ?NS_PUSH}], + attrs = #{<<"xmlns">> => ?NS_PUSH}, children = [make_form(?PUSH_FORM_TYPE, PushPayload)]} ]} ]} diff --git a/src/global_distrib/mod_global_distrib_connection.erl b/src/global_distrib/mod_global_distrib_connection.erl index 1a8594d7cab..39ce4017a77 100644 --- a/src/global_distrib/mod_global_distrib_connection.erl +++ b/src/global_distrib/mod_global_distrib_connection.erl @@ -129,5 +129,5 @@ opt(Key) -> mod_global_distrib_utils:opt(mod_global_distrib, Key). gd_start(Server, ConnID) -> - Attrs = [{<<"server">>, Server}, {<<"conn_id">>, ConnID}], + Attrs = #{<<"server">> => Server, <<"conn_id">> => ConnID}, exml:to_binary(#xmlel{name = <<"gd_start">>, attrs = Attrs}). diff --git a/src/global_distrib/mod_global_distrib_receiver.erl b/src/global_distrib/mod_global_distrib_receiver.erl index 00300d00e08..3cbee5127e4 100644 --- a/src/global_distrib/mod_global_distrib_receiver.erl +++ b/src/global_distrib/mod_global_distrib_receiver.erl @@ -183,7 +183,7 @@ do_receive_data(Socket, Buffer, RawData, State) -> -spec handle_data(Data :: binary(), state()) -> state(). handle_data(GdStart, State = #state{host = undefined}) -> {ok, #xmlel{name = <<"gd_start">>, attrs = Attrs}} = exml:parse(GdStart), - #{<<"server">> := Host, <<"conn_id">> := ConnId} = maps:from_list(Attrs), + #{<<"server">> := Host, <<"conn_id">> := ConnId} = Attrs, mongoose_instrument:execute(?GLOBAL_DISTRIB_INCOMING_FIRST_PACKET, #{}, #{count => 1, host => Host}), ?LOG_INFO(#{what => gd_incoming_connection, server => Host, conn_id => ConnId}), State#state{host = Host, conn_id = ConnId}; diff --git a/src/http_upload/mod_http_upload.erl b/src/http_upload/mod_http_upload.erl index 09696822b01..0d4caeda6b5 100644 --- a/src/http_upload/mod_http_upload.erl +++ b/src/http_upload/mod_http_upload.erl @@ -171,7 +171,7 @@ process_disco_iq(Acc, _From, _To, #iq{type = get, lang = Lang, sub_el = SubEl} = Features = mongoose_disco:features_to_xml([?NS_HTTP_UPLOAD_030]), {Acc, IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_DISCO_INFO}], + attrs = #{<<"xmlns">> => ?NS_DISCO_INFO}, children = Identity ++ Info ++ Features}]}}; _ -> ErrorMsg = <<"Node is not supported by HTTP upload">>, @@ -247,7 +247,7 @@ my_disco_name(Lang) -> compose_iq_reply(IQ, PutUrl, GetUrl, Headers) -> Slot = #xmlel{ name = <<"slot">>, - attrs = [{<<"xmlns">>, ?NS_HTTP_UPLOAD_030}], + attrs = #{<<"xmlns">> => ?NS_HTTP_UPLOAD_030}, children = [create_url_xmlel(<<"put">>, PutUrl, Headers), create_url_xmlel(<<"get">>, GetUrl, #{})]}, IQ#iq{type = result, sub_el =[Slot]}. @@ -278,7 +278,7 @@ file_too_large_error(MaxFileSize) -> MaxSizeEl = #xmlel{name = <<"max-file-size">>, children = [#xmlcdata{content = MaxFileSizeBin}]}, FileTooLargeEl = #xmlel{name = <<"file-too-large">>, - attrs = [{<<"xmlns">>, ?NS_HTTP_UPLOAD_030}], + attrs = #{<<"xmlns">> => ?NS_HTTP_UPLOAD_030}, children = [MaxSizeEl]}, Error0 = mongoose_xmpp_errors:not_acceptable(), Error0#xmlel{children = [FileTooLargeEl | Error0#xmlel.children]}. @@ -305,7 +305,7 @@ get_disco_info_form(MaxFileSizeBin) -> -spec header_to_xmlel({Key :: binary(), Value :: binary()}) -> exml:element(). header_to_xmlel({Key, Value}) -> #xmlel{name = <<"header">>, - attrs = [{<<"name">>, Key}], + attrs = #{<<"name">> => Key}, children = [#xmlcdata{content = Value}]}. @@ -313,7 +313,7 @@ header_to_xmlel({Key, Value}) -> exml:element(). create_url_xmlel(Name, Url, Headers) -> HeadersXml = [header_to_xmlel(H) || H <- maps:to_list(Headers)], - #xmlel{name = Name, attrs = [{<<"url">>, Url}], children = HeadersXml}. + #xmlel{name = Name, attrs = #{<<"url">> => Url}, children = HeadersXml}. -spec is_nonempty_binary(term()) -> boolean(). diff --git a/src/inbox/mod_inbox.erl b/src/inbox/mod_inbox.erl index cc4735fe608..12b62d72f3b 100644 --- a/src/inbox/mod_inbox.erl +++ b/src/inbox/mod_inbox.erl @@ -382,13 +382,13 @@ process_message(HostType, From, To, Message, _TS, Dir, Type) -> %% Stanza builders build_empty_bin(Num) -> #xmlel{name = <<"empty-bin">>, - attrs = [{<<"xmlns">>, ?NS_ESL_INBOX}], + attrs = #{<<"xmlns">> => ?NS_ESL_INBOX}, children = [#xmlel{name = <<"num">>, children = [#xmlcdata{content = integer_to_binary(Num)}]}]}. -spec build_inbox_message(mongoose_acc:t(), inbox_res(), jlib:iq()) -> exml:element(). build_inbox_message(Acc, InboxRes, IQ) -> - #xmlel{name = <<"message">>, attrs = [{<<"id">>, mongoose_bin:gen_from_timestamp()}], + #xmlel{name = <<"message">>, attrs = #{<<"id">> => mongoose_bin:gen_from_timestamp()}, children = [build_result_el(Acc, InboxRes, IQ)]}. -spec build_result_el(mongoose_acc:t(), inbox_res(), jlib:iq()) -> exml:element(). @@ -396,9 +396,9 @@ build_result_el(Acc, InboxRes = #{unread_count := Count}, #iq{id = IqId, sub_el AccTS = mongoose_acc:timestamp(Acc), Children = mod_inbox_utils:build_inbox_result_elements(InboxRes, AccTS), #xmlel{name = <<"result">>, - attrs = [{<<"xmlns">>, ?NS_ESL_INBOX}, - {<<"unread">>, integer_to_binary(Count)}, - {<<"queryid">>, exml_query:attr(QueryEl, <<"queryid">>, IqId)}], + attrs = #{<<"xmlns">> => ?NS_ESL_INBOX, + <<"unread">> => integer_to_binary(Count), + <<"queryid">> => exml_query:attr(QueryEl, <<"queryid">>, IqId)}, children = Children}. -spec build_result_iq([inbox_res()]) -> exml:element(). @@ -411,12 +411,12 @@ build_result_iq(List) -> #xmlel{name = K, children = [#xmlcdata{content = integer_to_binary(V)}]} end, Result), ResultSetEl = result_set(List), - #xmlel{name = <<"fin">>, attrs = [{<<"xmlns">>, ?NS_ESL_INBOX}], + #xmlel{name = <<"fin">>, attrs = #{<<"xmlns">> => ?NS_ESL_INBOX}, children = [ResultSetEl | maps:values(ResultBinary)]}. -spec result_set([inbox_res()]) -> exml:element(). result_set([]) -> - #xmlel{name = <<"set">>, attrs = [{<<"xmlns">>, ?NS_RSM}]}; + #xmlel{name = <<"set">>, attrs = #{<<"xmlns">> => ?NS_RSM}}; result_set([#{remote_jid := FirstBinJid, timestamp := FirstTS} | _] = List) -> #{remote_jid := LastBinJid, timestamp := LastTS} = lists:last(List), BFirst = mod_inbox_utils:encode_rsm_id(FirstTS, FirstBinJid), diff --git a/src/inbox/mod_inbox_entries.erl b/src/inbox/mod_inbox_entries.erl index b545f67329a..d126fc39a43 100644 --- a/src/inbox/mod_inbox_entries.erl +++ b/src/inbox/mod_inbox_entries.erl @@ -76,8 +76,8 @@ get_properties_for_jid(Acc, IQ, From, EntryJID, QueryType) -> Result -> Children = build_query_children(Acc, Result, IQ, QueryType), X = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_ESL_INBOX_CONVERSATION}, - {<<"jid">>, BinEntryJID}], + attrs = #{<<"xmlns">> => ?NS_ESL_INBOX_CONVERSATION, + <<"jid">> => BinEntryJID}, children = Children}], {Acc, IQ#iq{type = result, sub_el = X}} end. @@ -119,7 +119,7 @@ process_requests(Acc, IQ, From, EntryJID, Params) -> forward_result(Acc, IQ = #iq{id = IqId}, From, {_, _, ToBareJidBin}, Result) -> Children0 = build_query_children(Acc, Result, IQ, only_properties), Children1 = iq_x_wrapper(IQ, ToBareJidBin, Children0), - Msg = #xmlel{name = <<"message">>, attrs = [{<<"id">>, IqId}], children = Children1}, + Msg = #xmlel{name = <<"message">>, attrs = #{<<"id">> => IqId}, children = Children1}, Acc1 = ejabberd_router:route(From, jid:to_bare(From), Acc, Msg), Res = IQ#iq{type = result, sub_el = []}, {Acc1, Res}. @@ -127,9 +127,9 @@ forward_result(Acc, IQ = #iq{id = IqId}, From, {_, _, ToBareJidBin}, Result) -> -spec iq_x_wrapper(jlib:iq(), binary(), [exml:element()]) -> [exml:element()]. iq_x_wrapper(#iq{id = IqId, sub_el = Query}, Jid, Properties) -> [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_ESL_INBOX_CONVERSATION}, - {<<"jid">>, Jid}, - {<<"queryid">>, exml_query:attr(Query, <<"queryid">>, IqId)}], + attrs = #{<<"xmlns">> => ?NS_ESL_INBOX_CONVERSATION, + <<"jid">> => Jid, + <<"queryid">> => exml_query:attr(Query, <<"queryid">>, IqId)}, children = Properties}]. maybe_process_reset_stanza(Acc, From, IQ, ResetStanza) -> @@ -144,7 +144,7 @@ process_reset_stanza(Acc, From, IQ, _ResetStanza, InterlocutorJID) -> ok = mod_inbox_utils:reset_unread_count_to_zero(Acc, From, InterlocutorJID), Res = IQ#iq{type = result, sub_el = [#xmlel{name = <<"reset">>, - attrs = [{<<"xmlns">>, ?NS_ESL_INBOX_CONVERSATION}], + attrs = #{<<"xmlns">> => ?NS_ESL_INBOX_CONVERSATION}, children = []}]}, {Acc, Res}. diff --git a/src/inbox/mod_inbox_muclight.erl b/src/inbox/mod_inbox_muclight.erl index c7e703d3dea..004fa17ce4e 100644 --- a/src/inbox/mod_inbox_muclight.erl +++ b/src/inbox/mod_inbox_muclight.erl @@ -177,4 +177,4 @@ is_kicked_message(User, Packet) -> -spec get_users_with_affiliation(list(exml:element()), role()) -> list(exml:element()). get_users_with_affiliation(AffItems, Role) -> - [M || #xmlel{name = <<"user">>, attrs = [{<<"affiliation">>, R}]} = M <- AffItems, R == Role]. + [M || #xmlel{name = <<"user">>, attrs = #{<<"affiliation">> := R}} = M <- AffItems, R == Role]. diff --git a/src/inbox/mod_inbox_utils.erl b/src/inbox/mod_inbox_utils.erl index 246f1a3bf83..187a92448a1 100644 --- a/src/inbox/mod_inbox_utils.erl +++ b/src/inbox/mod_inbox_utils.erl @@ -166,7 +166,7 @@ fill_from_attr(Msg = #xmlel{attrs = Attrs}, From) -> case exml_query:attr(Msg, <<"from">>, undefined) of undefined -> FromBin = jid:to_binary(From), - Msg#xmlel{attrs = [{<<"from">>, FromBin} | Attrs]}; + Msg#xmlel{attrs = Attrs#{<<"from">> => FromBin}}; _ -> Msg end. @@ -240,7 +240,7 @@ build_inbox_entry_key(FromJid, ToJid) -> build_inbox_result_elements(#{msg := Content, timestamp := Timestamp, unread_count := UnreadCount, box := Box, muted_until := MutedUntil, extra := Extra}, AccTS) -> - [ #xmlel{name = <<"forwarded">>, attrs = [{<<"xmlns">>, ?NS_FORWARD}], + [ #xmlel{name = <<"forwarded">>, attrs = #{<<"xmlns">> => ?NS_FORWARD}, children = [build_delay_el(Timestamp), Content]}, kv_to_el(<<"read">>, mod_inbox_utils:bool_to_binary(0 =:= UnreadCount)), kv_to_el(<<"box">>, Box), diff --git a/src/jingle_sip/jingle_sip_callbacks.erl b/src/jingle_sip/jingle_sip_callbacks.erl index 73dec3b9f77..e9f96129da1 100644 --- a/src/jingle_sip/jingle_sip_callbacks.erl +++ b/src/jingle_sip/jingle_sip_callbacks.erl @@ -307,7 +307,7 @@ send_ringing_session_info(SIPMsg, ErrorCode) -> mod_jingle_sip_session:set_outgoing_handle(CallID, DialogHandle, FromJID, ToJID), RingingEl = #xmlel{name = <<"ringing">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:apps:rtp:info:1">>}]}, + attrs = #{<<"xmlns">> => <<"urn:xmpp:jingle:apps:rtp:info:1">>}}, JingleEl = jingle_sip_helper:jingle_element(CallID, <<"session-info">>, [RingingEl]), IQEl = jingle_sip_helper:jingle_iq(ToBinary, FromBinary, JingleEl), Acc = mongoose_acc:new(#{ location => ?LOCATION, @@ -337,7 +337,7 @@ path_to_res(Other) -> make_session_terminate_reason_el(ErrorCode, #sipmsg{class = {resp, ErrorCode, Binary}}) -> Reason = #xmlel{name = <<"general-error">>}, Details = #xmlel{name = <<"sip-error">>, - attrs = [{<<"code">>, integer_to_binary(ErrorCode)}], + attrs = #{<<"code">> => integer_to_binary(ErrorCode)}, children = [#xmlcdata{content = Binary}]}, #xmlel{name = <<"reason">>, children = [Reason, Details]}. diff --git a/src/jingle_sip/jingle_sip_helper.erl b/src/jingle_sip/jingle_sip_helper.erl index 16da661c8ee..37089499f49 100644 --- a/src/jingle_sip/jingle_sip_helper.erl +++ b/src/jingle_sip/jingle_sip_helper.erl @@ -28,19 +28,19 @@ exml:element(). jingle_element(CallID, Action, Children) -> #xmlel{name = <<"jingle">>, - attrs = [{<<"xmlns">>, ?JINGLE_NS}, - {<<"action">>, Action}, - {<<"sid">>, CallID}], + attrs = #{<<"xmlns">> => ?JINGLE_NS, + <<"action">> => Action, + <<"sid">> => CallID}, children = Children}. -spec jingle_iq(ToBinary :: jid:literal_jid(), FromBinary :: jid:literal_jid(), exml:element()) -> exml:element(). jingle_iq(ToBinary, FromBinary, JingleEl) -> #xmlel{name = <<"iq">>, - attrs = [{<<"from">>, FromBinary}, - {<<"to">>, ToBinary}, - {<<"id">>, uuid:uuid_to_string(uuid:get_v4(), binary_standard)}, - {<<"type">>, <<"set">>}], + attrs = #{<<"from">> => FromBinary, + <<"to">> => ToBinary, + <<"id">> => uuid:uuid_to_string(uuid:get_v4(), binary_standard), + <<"type">> => <<"set">>}, children = [JingleEl]}. -spec maybe_rewrite_to_phone(mongoose_acc:t()) -> jid:jid(). @@ -76,4 +76,3 @@ try_to_rewrite_from_phone(Server, PhoneNumber) -> {error, not_found} -> PhoneNumber end. - diff --git a/src/jingle_sip/jingle_to_sdp.erl b/src/jingle_sip/jingle_to_sdp.erl index 614d876970d..dfe2ee3e4ba 100644 --- a/src/jingle_sip/jingle_to_sdp.erl +++ b/src/jingle_sip/jingle_to_sdp.erl @@ -205,37 +205,35 @@ parse_transport_child(#xmlel{name = <<"fingerprint">>} = FingerprintEl, Transpor Transport#{fingerprint => {Hash, Setup, Fingerprint}}; parse_transport_child(#xmlel{name = <<"candidate">>, attrs = Attrs}, #{candidates := Candidates} = Transport) -> - NewCandidate = lists:foldl(fun parse_candidate_attr/2, #{}, Attrs), + NewCandidate = maps:fold(fun parse_candidate_attr/3, #{}, Attrs), Transport#{candidates := [NewCandidate | Candidates]}; parse_transport_child(_, Transport) -> Transport. --spec parse_candidate_attr({binary(), any()}, map()) -> map(). -parse_candidate_attr({<<"foundation">>, Val}, Map) -> +-spec parse_candidate_attr(binary(), any(), map()) -> map(). +parse_candidate_attr(<<"foundation">>, Val, Map) -> Map#{foundation => Val}; -parse_candidate_attr({<<"component">>, Val}, Map) -> - Map#{component => Val}; -parse_candidate_attr({<<"generation">>, Val}, Map) -> +parse_candidate_attr(<<"component">>, Val, Map) -> Map#{generation => Val}; -parse_candidate_attr({<<"id">>, Val}, Map) -> +parse_candidate_attr(<<"id">>, Val, Map) -> Map#{id => Val}; -parse_candidate_attr({<<"ip">>, Val}, Map) -> +parse_candidate_attr(<<"ip">>, Val, Map) -> Map#{ip => Val}; -parse_candidate_attr({<<"network">>, Val}, Map) -> +parse_candidate_attr(<<"network">>, Val, Map) -> Map#{network => Val}; -parse_candidate_attr({<<"port">>, Val}, Map) -> +parse_candidate_attr(<<"port">>, Val, Map) -> Map#{port => Val}; -parse_candidate_attr({<<"priority">>, Val}, Map) -> +parse_candidate_attr(<<"priority">>, Val, Map) -> Map#{priority => Val}; -parse_candidate_attr({<<"protocol">>, Val}, Map) -> +parse_candidate_attr(<<"protocol">>, Val, Map) -> Map#{protocol => Val}; -parse_candidate_attr({<<"rel-addr">>, Val}, Map) -> +parse_candidate_attr(<<"rel-addr">>, Val, Map) -> Map#{raddr => Val}; -parse_candidate_attr({<<"rel-port">>, Val}, Map) -> +parse_candidate_attr(<<"rel-port">>, Val, Map) -> Map#{rport => Val}; -parse_candidate_attr({<<"tcptype">>, Val}, Map) -> +parse_candidate_attr(<<"tcptype">>, Val, Map) -> Map#{tcptype => Val}; -parse_candidate_attr({<<"type">>, Val}, Map) -> +parse_candidate_attr(<<"type">>, Val, Map) -> Map#{type => Val}; -parse_candidate_attr(_, Map) -> +parse_candidate_attr(_, _, Map) -> Map. diff --git a/src/jingle_sip/sip_to_jingle.erl b/src/jingle_sip/sip_to_jingle.erl index fdd839f1500..60e0fb12130 100644 --- a/src/jingle_sip/sip_to_jingle.erl +++ b/src/jingle_sip/sip_to_jingle.erl @@ -37,8 +37,8 @@ parse_sdp_attributes([Attr | Rest], Acc) -> parse_sdp_attribute({<<"group">>, [Method | Contents]}, Acc) -> ContentEls = [sdp_group_content_to_el(Content) || Content <- Contents], El = #xmlel{name = <<"group">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:apps:grouping:0">>}, - {<<"semantics">>, Method}], + attrs = #{<<"xmlns">> => <<"urn:xmpp:jingle:apps:grouping:0">>, + <<"semantics">> => Method}, children = ContentEls}, [El | Acc]; parse_sdp_attribute(_, Acc) -> @@ -46,7 +46,7 @@ parse_sdp_attribute(_, Acc) -> sdp_group_content_to_el(Content) -> #xmlel{name = <<"content">>, - attrs = [{<<"name">>, Content}]}. + attrs = #{<<"name">> => Content}}. %% This function assumes that all codecs and their attributes were @@ -59,25 +59,25 @@ sdp_media_to_content_el(#sdp_m{media = Media, attributes = Attrs}, CodecMap) -> AdditionalDescriptionEls = description_elements_from_content(Content), DescriptionEl = #xmlel{name = <<"description">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:apps:rtp:1">>}, - {<<"media">>, Media}], + attrs = #{<<"xmlns">> => <<"urn:xmpp:jingle:apps:rtp:1">>, + <<"media">> => Media}, children = PayloadEls ++ AdditionalDescriptionEls}, TransportEl = make_transport_el(maps:get(transport, Content)), #xmlel{name = <<"content">>, - attrs = [{<<"creator">>, <<"initiator">>}, - {<<"name">>, maps:get(name, Content, Media)}, - {<<"senders">>, maps:get(sender, Content)}], + attrs = #{<<"creator">> => <<"initiator">>, + <<"name">> => maps:get(name, Content, Media), + <<"senders">> => maps:get(sender, Content)}, children = [DescriptionEl, TransportEl]}. codec_to_payload({ID, RTPMap, Attrs}) -> Parameters = lists:flatmap(fun codec_attr_to_params/1, Attrs), {Name, ClockRate, Channels} = parse_codec_rtpmap(RTPMap), #xmlel{name = <<"payload-type">>, - attrs = [{<<"id">>, ID}, - {<<"name">>, Name}, - {<<"clockrate">>, ClockRate}, - {<<"channels">>, Channels}], + attrs = #{<<"id">> => ID, + <<"name">> => Name, + <<"clockrate">> => ClockRate, + <<"channels">> => Channels}, children = Parameters}. parse_codec_rtpmap(RTPMap) -> @@ -91,7 +91,7 @@ parse_codec_rtpmap(RTPMap) -> codec_attr_to_params({<<"rtcp-fb">>, Value}) -> Attrs = rtcp_fb_value_to_xml_attrs(Value), [#xmlel{name = <<"rtcp-fb">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:apps:rtp:rtcp-fb:0">>} | Attrs]}]; + attrs = Attrs#{<<"xmlns">> => <<"urn:xmpp:jingle:apps:rtp:rtcp-fb:0">>}}]; codec_attr_to_params({<<"fmtp">>, [Value]}) -> Params = binary:split(Value, <<$;>>, [global]), [basic_param_to_xml_el(Param) || Param <- Params]; @@ -99,19 +99,19 @@ codec_attr_to_params(_) -> []. rtcp_fb_value_to_xml_attrs([Type]) -> - [{<<"type">>, Type}]; + #{<<"type">> => Type}; rtcp_fb_value_to_xml_attrs([Type, SubType]) -> - [{<<"type">>, Type}, {<<"subtype">>, SubType}]. + #{<<"type">> => Type, <<"subtype">> => SubType}. basic_param_to_xml_el(Param) -> case binary:split(Param, <<$=>>) of [Name, Value] -> #xmlel{name = <<"parameter">>, - attrs = [{<<"name">>, Name}, - {<<"value">>, Value}]}; + attrs = #{<<"name">> => Name, + <<"value">> => Value}}; [Value] -> #xmlel{name = <<"parameter">>, - attrs = [{<<"value">>, Value}]} + attrs = #{<<"value">> => Value}} end. parse_nksip_media_attrs(Attrs) -> @@ -196,10 +196,10 @@ description_elements_from_content(Content) -> rtphdr_ext_to_element({ID, Sender, URI}) -> #xmlel{name = <<"rtp-hdrext">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:apps:rtp:rtp-hdrext:0">>}, - {<<"id">>, ID}, - {<<"uri">>, URI}, - {<<"senders">>, Sender}]}. + attrs = #{<<"xmlns">> => <<"urn:xmpp:jingle:apps:rtp:rtp-hdrext:0">>, + <<"id">> => ID, + <<"uri">> => URI, + <<"senders">> => Sender}}. maybe_add_rtcp_mux(#{rtcp_mux := true}, Els) -> El = #xmlel{name = <<"rtcp-mux">>}, @@ -233,42 +233,41 @@ parse_candidate_extra_args(Rest, Candidate) -> make_transport_el(Transport) -> CandidateElements = [make_candidate_el(Candidate) || Candidate <- maps:get(candidates, Transport, [])], - AttrsWithUfrag = maybe_add_ice_ufrag(maps:get(ufrag, Transport, undefined), []), + AttrsWithUfrag = maybe_add_ice_ufrag(maps:get(ufrag, Transport, undefined), #{}), ICEAttrs = maybe_add_ice_pwd(maps:get(pwd, Transport, undefined), AttrsWithUfrag), El = #xmlel{name = <<"transport">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:transports:ice-udp:1">>} | - ICEAttrs], + attrs = ICEAttrs#{<<"xmlns">> => <<"urn:xmpp:jingle:transports:ice-udp:1">>}, children = CandidateElements}, maybe_add_fingerprint_el(Transport, El). make_candidate_el(Candidate) -> - Attrs = maps:fold(fun candidate_kv_to_attr/3, [], Candidate), + Attrs = maps:fold(fun candidate_kv_to_attr/3, #{}, Candidate), #xmlel{name = <<"candidate">>, attrs = Attrs}. candidate_kv_to_attr(raddr, Value, Acc) -> - [{<<"rel-addr">>, Value} | Acc]; + Acc#{<<"rel-addr">> => Value}; candidate_kv_to_attr(rport, Value, Acc) -> - [{<<"rel-port">>, Value} | Acc]; + Acc#{<<"rel-port">> => Value}; candidate_kv_to_attr(Key, Value, Acc) -> - [{erlang:atom_to_binary(Key, utf8), Value} | Acc]. + Acc#{erlang:atom_to_binary(Key, utf8) => Value}. maybe_add_ice_ufrag(undefined, Attrs) -> Attrs; maybe_add_ice_ufrag(Ufrag, Attrs) -> - [{<<"ufrag">>, Ufrag} | Attrs]. + Attrs#{<<"ufrag">> => Ufrag}. maybe_add_ice_pwd(undefined, Attrs) -> Attrs; maybe_add_ice_pwd(Pwd, Attrs) -> - [{<<"pwd">>, Pwd} | Attrs]. + Attrs#{<<"pwd">> => Pwd}. maybe_add_fingerprint_el(#{fingerprint := {Hash, Fingerprint}} = Transport, #xmlel{children = Children} = El) -> - Attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:apps:dtls:0">>}, - {<<"hash">>, Hash}], + Attrs = #{<<"xmlns">> => <<"urn:xmpp:jingle:apps:dtls:0">>, + <<"hash">> => Hash}, AllAttrs = maybe_add_setup_attr(maps:get(setup, Transport, undefined), Attrs), FingerprintEl = #xmlel{name = <<"fingerprint">>, attrs = AllAttrs, @@ -278,7 +277,7 @@ maybe_add_fingerprint_el(#{fingerprint := {Hash, Fingerprint}} = Transport, maybe_add_setup_attr(undefined, Attrs) -> Attrs; maybe_add_setup_attr(Setup, Attrs) -> - [{<<"setup">>, Setup} | Attrs]. + Attrs#{<<"setup">> => Setup}. decode_ssrc_sdp_param(Parameter) -> Bin = list_to_binary(lists:join(" ", Parameter)), @@ -298,8 +297,8 @@ maybe_add_sources(_, Els) -> source_to_el(SSRC, Params) -> Parameters = [ssrc_attr_to_el(Attr) || Attr <- Params], #xmlel{name = <<"source">>, - attrs = [{<<"xmlns">>, <<"urn:xmpp:jingle:apps:rtp:ssma:0">>}, - {<<"ssrc">>, SSRC}], + attrs = #{<<"xmlns">> => <<"urn:xmpp:jingle:apps:rtp:ssma:0">>, + <<"ssrc">> => SSRC}, children = Parameters}. ssrc_attr_to_el(Attr) -> @@ -308,9 +307,7 @@ ssrc_attr_to_el(Attr) -> attrs = Attrs}. make_el_attrs_from_ssrc({Attr, Value}) -> - [{<<"name">>, Attr}, - {<<"value">>, Value}]; + #{<<"name">> => Attr, + <<"value">> => Value}; make_el_attrs_from_ssrc(Attr) -> - [{<<"name">>, Attr}]. - - + #{<<"name">> => Attr}. diff --git a/src/jlib.erl b/src/jlib.erl index 7f8a2aca92d..8b177f3de3d 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -85,6 +85,8 @@ iq/0, rfc3339_string/0]). +-define(IS_EMPTY(X), (X =:= #{})). + -spec make_result_iq_reply(exml:element()) -> exml:element(); (iq()) -> iq(). make_result_iq_reply(XE = #xmlel{}) -> @@ -93,28 +95,10 @@ make_result_iq_reply(XE = #xmlel{}) -> make_result_iq_reply(IQ = #iq{}) -> IQ#iq{type = result}. - --spec make_result_iq_reply_attrs(exml:element()) -> [exml:attr(), ...]. -make_result_iq_reply_attrs(#xmlel{attrs = Attrs} = Element) -> - To = exml_query:attr(Element, <<"to">>), - From = exml_query:attr(Element, <<"from">>), - Attrs1 = lists:keydelete(<<"to">>, 1, Attrs), - Attrs2 = lists:keydelete(<<"from">>, 1, Attrs1), - Attrs3 = case To of - undefined -> - Attrs2; - ToVal -> - [{<<"from">>, ToVal} | Attrs2] - end, - Attrs4 = case From of - undefined -> - Attrs3; - FromVal -> - [{<<"to">>, FromVal} | Attrs3] - end, - Attrs5 = lists:keydelete(<<"type">>, 1, Attrs4), - [{<<"type">>, <<"result">>} | Attrs5]. - +-spec make_result_iq_reply_attrs(exml:element()) -> exml:attrs(). +make_result_iq_reply_attrs(#xmlel{attrs = Attrs}) -> + Attrs1 = swap_from_to_attrs(Attrs), + Attrs1#{<<"type">> => <<"result">>}. -spec make_error_reply(exml:element() | mongoose_acc:t(), xmlcdata() | exml:element()) -> @@ -143,34 +127,18 @@ make_error_reply_from_element(#xmlel{name = Name, children = SubTags} = Element, NewAttrs = make_error_reply_attrs(Element), #xmlel{name = Name, attrs = NewAttrs, children = [Error | SubTags]}. --spec make_error_reply_attrs(exml:element()) -> [exml:attr(), ...]. -make_error_reply_attrs(#xmlel{attrs = Attrs} = Element) -> - To = exml_query:attr(Element, <<"to">>), - From = exml_query:attr(Element, <<"from">>), - Attrs1 = lists:keydelete(<<"to">>, 1, Attrs), - Attrs2 = lists:keydelete(<<"from">>, 1, Attrs1), - Attrs3 = case To of - undefined -> - Attrs2; - ToVal -> - [{<<"from">>, ToVal} | Attrs2] - end, - Attrs4 = case From of - undefined -> - Attrs3; - FromVal -> - [{<<"to">>, FromVal} | Attrs3] - end, - Attrs5 = lists:keydelete(<<"type">>, 1, Attrs4), - [{<<"type">>, <<"error">>} | Attrs5]. +-spec make_error_reply_attrs(exml:element()) -> exml:attrs(). +make_error_reply_attrs(#xmlel{attrs = Attrs}) -> + Attrs1 = swap_from_to_attrs(Attrs), + Attrs1#{<<"type">> => <<"error">>}. -spec make_config_change_message(binary()) -> exml:element(). make_config_change_message(Status) -> - #xmlel{name = <<"message">>, attrs = [{<<"type">>, <<"groupchat">>}], + #xmlel{name = <<"message">>, attrs = #{<<"type">> => <<"groupchat">>}, children = [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], + attrs = #{<<"xmlns">> => ?NS_MUC_USER}, children = [#xmlel{name = <<"status">>, - attrs = [{<<"code">>, Status}]}]}]}. + attrs = #{<<"code">> => Status}}]}]}. -spec make_invitation(From :: jid:jid(), Password :: binary(), @@ -182,7 +150,7 @@ make_invitation(From, Password, Reason) -> children = [#xmlcdata{content = Reason}]}] end, Elements = [#xmlel{name = <<"invite">>, - attrs = [{<<"from">>, jid:to_binary(From)}], + attrs = #{<<"from">> => jid:to_binary(From)}, children = Children}], Elements2 = case Password of @@ -193,22 +161,31 @@ make_invitation(From, Password, Reason) -> #xmlel{name = <<"message">>, children = [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], + attrs = #{<<"xmlns">> => ?NS_MUC_USER}, children = Elements2}]}. -spec replace_from_to_attrs(From :: binary(), To :: binary() | undefined, - [exml:attr()]) -> [exml:attr()]. + exml:attrs()) -> exml:attrs(). replace_from_to_attrs(From, To, Attrs) -> - Attrs1 = lists:keydelete(<<"to">>, 1, Attrs), - Attrs2 = lists:keydelete(<<"from">>, 1, Attrs1), - Attrs3 = case To of - undefined -> Attrs2; - _ -> [{<<"to">>, To} | Attrs2] + Attrs1 = maps:without([<<"from">>, <<"to">>], Attrs), + Attrs2 = case To of + undefined -> Attrs1; + _ -> Attrs1#{<<"to">> => To} end, - Attrs4 = [{<<"from">>, From} | Attrs3], - Attrs4. - + Attrs2#{<<"from">> => From}. + +-spec swap_from_to_attrs(exml:attrs()) -> exml:attrs(). +swap_from_to_attrs(#{<<"from">> := From, <<"to">> := To} = Attrs) -> + Attrs#{<<"from">> := To, <<"to">> := From}; +swap_from_to_attrs(#{<<"from">> := From} = Attrs0) -> + Attrs1 = maps:remove(<<"from">>, Attrs0), + Attrs1#{<<"to">> => From}; +swap_from_to_attrs(#{<<"to">> := To} = Attrs0) -> + Attrs1 = maps:remove(<<"to">>, Attrs0), + Attrs1#{<<"from">> => To}; +swap_from_to_attrs(Attrs) -> + Attrs. -spec replace_from_to(From :: jid:simple_jid() | jid:jid(), To :: jid:simple_jid() | jid:jid(), @@ -222,7 +199,7 @@ replace_from_to(From, To, XE = #xmlel{attrs = Attrs}) -> -spec remove_attr(binary(), exml:element()) -> exml:element(). remove_attr(Attr, XE = #xmlel{attrs = Attrs}) -> - NewAttrs = lists:keydelete(Attr, 1, Attrs), + NewAttrs = maps:remove(Attr, Attrs), XE#xmlel{attrs = NewAttrs}. -spec iq_query_info(exml:element()) -> 'invalid' | 'not_iq' | 'reply' | iq(). @@ -310,11 +287,11 @@ iq_type_to_binary(_) -> invalid. -spec iq_to_xml(iq()) -> exml:element(). iq_to_xml(#iq{id = ID, type = Type, sub_el = SubEl}) when ID /= "" -> #xmlel{name = <<"iq">>, - attrs = [{<<"id">>, ID}, {<<"type">>, iq_type_to_binary(Type)}], + attrs = #{<<"id">> => ID, <<"type">> => iq_type_to_binary(Type)}, children = sub_el_to_els(SubEl)}; iq_to_xml(#iq{type = Type, sub_el = SubEl}) -> #xmlel{name = <<"iq">>, - attrs = [{<<"type">>, iq_type_to_binary(Type)}], + attrs = #{<<"type">> => iq_type_to_binary(Type)}, children = sub_el_to_els(SubEl)}. %% @doc Convert `#iq.sub_el' back to `#xmlel.children'. @@ -337,17 +314,17 @@ rsm_decode(#xmlel{} = SubEl) -> end. -spec rsm_parse_element(exml:element(), rsm_in()) -> rsm_in(). -rsm_parse_element(#xmlel{name = <<"max">>, attrs = []} = Elem, RsmIn) -> +rsm_parse_element(#xmlel{name = <<"max">>, attrs = Attrs} = Elem, RsmIn) when ?IS_EMPTY(Attrs) -> CountStr = exml_query:cdata(Elem), {Count, _} = string:to_integer(binary_to_list(CountStr)), RsmIn#rsm_in{max = Count}; -rsm_parse_element(#xmlel{name = <<"before">>, attrs = []} = Elem, RsmIn) -> +rsm_parse_element(#xmlel{name = <<"before">>, attrs = Attrs} = Elem, RsmIn) when ?IS_EMPTY(Attrs) -> UID = exml_query:cdata(Elem), RsmIn#rsm_in{direction = before, id = UID}; -rsm_parse_element(#xmlel{name = <<"after">>, attrs = []} = Elem, RsmIn) -> +rsm_parse_element(#xmlel{name = <<"after">>, attrs = Attrs} = Elem, RsmIn) when ?IS_EMPTY(Attrs) -> UID = exml_query:cdata(Elem), RsmIn#rsm_in{direction = aft, id = UID}; -rsm_parse_element(#xmlel{name = <<"index">>, attrs = []} = Elem, RsmIn) -> +rsm_parse_element(#xmlel{name = <<"index">>, attrs = Attrs} = Elem, RsmIn) when ?IS_EMPTY(Attrs) -> IndexStr = exml_query:cdata(Elem), {Index, _} = string:to_integer(binary_to_list(IndexStr)), RsmIn#rsm_in{index = Index}; @@ -358,7 +335,7 @@ rsm_parse_element(_, RsmIn)-> rsm_encode(none) -> []; rsm_encode(RsmOut) -> - [#xmlel{name = <<"set">>, attrs = [{<<"xmlns">>, ?NS_RSM}], + [#xmlel{name = <<"set">>, attrs = #{<<"xmlns">> => ?NS_RSM}, children = lists:reverse(rsm_encode_out(RsmOut))}]. -spec rsm_encode_out(rsm_out()) -> [exml:element()]. @@ -375,7 +352,7 @@ rsm_encode_first(undefined, undefined, Arr) -> rsm_encode_first(First, undefined, Arr) -> [#xmlel{name = <<"first">>, children = [#xmlcdata{content = First}]} | Arr]; rsm_encode_first(First, Index, Arr) -> - [#xmlel{name = <<"first">>, attrs = [{<<"index">>, i2b(Index)}], + [#xmlel{name = <<"first">>, attrs = #{<<"index">> => i2b(Index)}, children = [#xmlcdata{content = First}]}|Arr]. -spec rsm_encode_last(Last :: 'undefined', Arr :: [exml:element()]) -> [exml:element()]. @@ -402,12 +379,12 @@ timestamp_to_xml(TimestampString, FromJID, Desc) -> _ -> [#xmlcdata{content = Desc}] end, From = case FromJID of - undefined -> []; - _ -> [{<<"from">>, jid:to_binary(FromJID)}] + undefined -> #{}; + _ -> #{<<"from">> =>jid:to_binary(FromJID)} end, #xmlel{name = <<"delay">>, - attrs = [{<<"xmlns">>, ?NS_DELAY}, - {<<"stamp">>, list_to_binary(TimestampString)} | From], + attrs = From#{<<"xmlns">> => ?NS_DELAY, + <<"stamp">> => list_to_binary(TimestampString)}, children = Text}. -spec stanza_error( Code :: binary() @@ -417,7 +394,7 @@ timestamp_to_xml(TimestampString, FromJID, Desc) -> , SpecNs :: binary() | undefined) -> exml:element(). stanza_error(Code, Type, Condition, SpecTag, SpecNs) -> Er = stanza_error(Code, Type, Condition), - Spec = #xmlel{ name = SpecTag, attrs = [{<<"xmlns">>, SpecNs}]}, + Spec = #xmlel{ name = SpecTag, attrs = #{<<"xmlns">> => SpecNs}}, NCh = [Spec | Er#xmlel.children], Er#xmlel{children = NCh}. @@ -428,9 +405,9 @@ stanza_error(Code, Type, Condition, SpecTag, SpecNs) -> , Condition :: binary() | undefined) -> exml:element(). stanza_error(Code, Type, Condition) -> #xmlel{ name = <<"error">> - , attrs = [{<<"code">>, Code}, {<<"type">>, Type}] - , children = [ #xmlel{ name = Condition - , attrs = [{<<"xmlns">>, ?NS_STANZAS}] + , attrs = #{<<"code">> => Code, <<"type">> => Type} + , children = [ #xmlel{ name = Condition + , attrs = #{<<"xmlns">> => ?NS_STANZAS} }] }. @@ -442,12 +419,12 @@ stanza_error(Code, Type, Condition) -> stanza_errort(Code, Type, Condition, Lang, Text) -> Txt = translate:translate(Lang, Text), #xmlel{ name = <<"error">> - , attrs = [{<<"code">>, Code}, {<<"type">>, Type}] + , attrs = #{<<"code">> => Code, <<"type">> => Type} , children = [ #xmlel{ name = Condition - , attrs = [{<<"xmlns">>, ?NS_STANZAS}] + , attrs = #{<<"xmlns">> => ?NS_STANZAS} } , #xmlel{ name = <<"text">> - , attrs = [{<<"xmlns">>, ?NS_STANZAS}] + , attrs = #{<<"xmlns">> => ?NS_STANZAS} , children = [#xmlcdata{ content = Txt }] }] }. @@ -456,7 +433,7 @@ stanza_errort(Code, Type, Condition, Lang, Text) -> stream_error(Condition) -> #xmlel{ name = <<"stream:error">> , children = [ #xmlel{ name = Condition - , attrs = [{<<"xmlns">>, ?NS_STREAMS}] + , attrs = #{<<"xmlns">> => ?NS_STREAMS} } ] }. @@ -468,10 +445,10 @@ stream_errort(Condition, Lang, Text) -> Txt = translate:translate(Lang, Text), #xmlel{ name = <<"stream:error">> , children = [ #xmlel{ name = Condition - , attrs = [{<<"xmlns">>, ?NS_STREAMS}] } + , attrs = #{<<"xmlns">> => ?NS_STREAMS} } , #xmlel{ name = <<"text">> - , attrs = [ {<<"xml:lang">>, Lang} - , {<<"xmlns">>, ?NS_STREAMS}] + , attrs = #{ <<"xml:lang">> => Lang + , <<"xmlns">> => ?NS_STREAMS} , children = [ #xmlcdata{ content = Txt} ]} ] }. @@ -526,9 +503,8 @@ append_subtags(XE = #xmlel{children = SubTags1}, SubTags2) -> -spec replace_tag_attr(Attr :: binary(), Value :: binary(), exml:element() ) -> exml:element(). replace_tag_attr(Attr, Value, XE = #xmlel{attrs = Attrs}) -> - Attrs1 = lists:keydelete(Attr, 1, Attrs), - Attrs2 = [{Attr, Value} | Attrs1], - XE#xmlel{attrs = Attrs2}. + Attrs1 = Attrs#{Attr => Value}, + XE#xmlel{attrs = Attrs1}. %% @doc Given an element and a new subelement, %% replace the instance of the subelement in element with the new subelement. diff --git a/src/mam/mam_message.erl b/src/mam/mam_message.erl index befb84e625a..366391a931f 100644 --- a/src/mam/mam_message.erl +++ b/src/mam/mam_message.erl @@ -35,5 +35,5 @@ error_stanza() -> Err = mongoose_xmpp_errors:internal_server_error(<<"en">>, Text), Body = #xmlel{name = <<"body">>, children = [#xmlcdata{content = Text}]}, #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"error">>}], + attrs = #{<<"type">> => <<"error">>}, children = [Err, Body]}. diff --git a/src/mam/mod_mam_utils.erl b/src/mam/mod_mam_utils.erl index 6993a7f32b9..27ee08a2a24 100644 --- a/src/mam/mod_mam_utils.erl +++ b/src/mam/mod_mam_utils.erl @@ -243,11 +243,15 @@ maybe_log_deprecation(_IQ) -> %% @doc Return true, if the first element points on `By'. -spec is_arcid_elem_for(ElemName :: binary(), exml:element(), By :: binary()) -> boolean(). -is_arcid_elem_for(<<"archived">>, #xmlel{name = <<"archived">>, attrs=As}, By) -> - lists:member({<<"by">>, By}, As); -is_arcid_elem_for(<<"stanza-id">>, #xmlel{name = <<"stanza-id">>, attrs=As}, By) -> - lists:member({<<"by">>, By}, As) andalso - lists:member({<<"xmlns">>, ?NS_STANZAID}, As); +is_arcid_elem_for(<<"archived">>, #xmlel{name = <<"archived">>, + attrs = #{<<"by">> := By}}, By) -> + true; +is_arcid_elem_for(<<"stanza-id">>, + #xmlel{name = <<"stanza-id">>, + attrs = #{<<"by">> := By, + <<"xmlns">> := ?NS_STANZAID}}, + By) -> + true; is_arcid_elem_for(_, _, _) -> false. @@ -262,12 +266,15 @@ replace_arcid_elem(ElemName, By, Id, Packet) -> append_arcid_elem(<<"stanza-id">>, By, Id, Packet) -> Archived = #xmlel{ name = <<"stanza-id">>, - attrs=[{<<"by">>, By}, {<<"id">>, Id}, {<<"xmlns">>, ?NS_STANZAID}]}, + attrs=#{<<"by">> => By, + <<"id">> => Id, + <<"xmlns">> => ?NS_STANZAID}}, jlib:append_subtags(Packet, [Archived]); append_arcid_elem(ElemName, By, Id, Packet) -> Archived = #xmlel{ name = ElemName, - attrs=[{<<"by">>, By}, {<<"id">>, Id}]}, + attrs=#{<<"by">> => By, + <<"id">> => Id}}, jlib:append_subtags(Packet, [Archived]). -spec delete_arcid_elem(ElemName :: binary(), By :: binary(), exml:element()) -> exml:element(). @@ -275,8 +282,8 @@ delete_arcid_elem(ElemName, By, Packet=#xmlel{children=Cs}) -> Packet#xmlel{children=[C || C <- Cs, not is_arcid_elem_for(ElemName, C, By)]}. -is_x_user_element(#xmlel{name = <<"x">>, attrs = As}) -> - lists:member({<<"xmlns">>, ?NS_MUC_USER}, As); +is_x_user_element(#xmlel{name = <<"x">>, attrs = #{<<"xmlns">> := ?NS_MUC_USER}}) -> + true; is_x_user_element(_) -> false. @@ -290,16 +297,16 @@ append_x_user_element(FromJID, Role, Affiliation, Packet) -> ItemElem = x_user_item(FromJID, Role, Affiliation), X = #xmlel{ name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], + attrs = #{<<"xmlns">> => ?NS_MUC_USER}, children = [ItemElem]}, jlib:append_subtags(Packet, [X]). x_user_item(FromJID, Role, Affiliation) -> #xmlel{ name = <<"item">>, - attrs = [{<<"affiliation">>, atom_to_binary(Affiliation, latin1)}, - {<<"jid">>, jid:to_binary(FromJID)}, - {<<"role">>, atom_to_binary(Role, latin1)}]}. + attrs = #{<<"affiliation">> => atom_to_binary(Affiliation, latin1), + <<"jid">> => jid:to_binary(FromJID), + <<"role">> => atom_to_binary(Role, latin1)}}. -spec delete_x_user_element(exml:element()) -> exml:element(). delete_x_user_element(Packet=#xmlel{children=Cs}) -> @@ -451,11 +458,11 @@ retracted_element(#{retract_on := origin_id, origin_id := OriginID}, _LocJid) -> Timestamp = calendar:system_time_to_rfc3339(erlang:system_time(second), [{offset, "Z"}]), #xmlel{name = <<"retracted">>, - attrs = [{<<"xmlns">>, ?NS_RETRACT}, - {<<"stamp">>, list_to_binary(Timestamp)}], + attrs = #{<<"xmlns">> => ?NS_RETRACT, + <<"stamp">> => list_to_binary(Timestamp)}, children = [#xmlel{name = <<"origin-id">>, - attrs = [{<<"xmlns">>, ?NS_STANZAID}, - {<<"id">>, OriginID}]} + attrs = #{<<"xmlns">> => ?NS_STANZAID, + <<"id">> => OriginID}} ]}; retracted_element(#{retract_on := stanza_id, message_id := MessID} = Env, LocJid) -> @@ -463,18 +470,18 @@ retracted_element(#{retract_on := stanza_id, StanzaID = mod_mam_utils:mess_id_to_external_binary(MessID), MaybeOriginId = maybe_append_origin_id(Env), #xmlel{name = <<"retracted">>, - attrs = [{<<"xmlns">>, ?NS_ESL_RETRACT}, - {<<"stamp">>, list_to_binary(Timestamp)}], + attrs = #{<<"xmlns">> => ?NS_ESL_RETRACT, + <<"stamp">> => list_to_binary(Timestamp)}, children = [#xmlel{name = <<"stanza-id">>, - attrs = [{<<"xmlns">>, ?NS_STANZAID}, - {<<"id">>, StanzaID}, - {<<"by">>, jid:to_bare_binary(LocJid)}]} | + attrs = #{<<"xmlns">> => ?NS_STANZAID, + <<"id">> => StanzaID, + <<"by">> => jid:to_bare_binary(LocJid)}} | MaybeOriginId ]}. -spec maybe_append_origin_id(retraction_info()) -> [exml:element()]. maybe_append_origin_id(#{origin_id := OriginID}) when is_binary(OriginID), <<>> =/= OriginID -> - [#xmlel{name = <<"origin-id">>, attrs = [{<<"xmlns">>, ?NS_STANZAID}, {<<"id">>, OriginID}]}]; + [#xmlel{name = <<"origin-id">>, attrs = #{<<"xmlns">> => ?NS_STANZAID, <<"id">> => OriginID}}]; maybe_append_origin_id(_) -> []. @@ -491,7 +498,7 @@ wrap_message(MamNs, Packet, QueryID, MessageUID, TS, SrcJID) -> SrcJID :: jid:jid()) -> Wrapper :: exml:element(). wrap_message(MamNs, Packet, QueryID, MessageUID, WrapperID, TS, SrcJID) -> #xmlel{ name = <<"message">>, - attrs = [{<<"id">>, WrapperID}], + attrs = #{<<"id">> => WrapperID}, children = [result(MamNs, QueryID, MessageUID, [forwarded(Packet, TS, SrcJID)])] }. @@ -500,7 +507,7 @@ wrap_message(MamNs, Packet, QueryID, MessageUID, WrapperID, TS, SrcJID) -> forwarded(Packet, TS, SrcJID) -> #xmlel{ name = <<"forwarded">>, - attrs = [{<<"xmlns">>, ?NS_FORWARD}], + attrs = #{<<"xmlns">> => ?NS_FORWARD}, %% Two places to include SrcJID: %% - delay.from - optional XEP-0297 (TODO: depricate adding it?) %% - message.from - required XEP-0313 @@ -512,9 +519,7 @@ delay(TS, SrcJID) -> jlib:timestamp_to_xml(TS, SrcJID, <<>>). replace_from_attribute(From, Packet=#xmlel{attrs = Attrs}) -> - Attrs1 = lists:keydelete(<<"from">>, 1, Attrs), - Attrs2 = [{<<"from">>, jid:to_binary(From)} | Attrs1], - Packet#xmlel{attrs = Attrs2}. + Packet#xmlel{attrs = Attrs#{<<"from">> => jid:to_binary(From)}}. %% @doc Generates tag `'. %% This element will be added in each forwarded message. @@ -522,11 +527,15 @@ replace_from_attribute(From, Packet=#xmlel{attrs = Attrs}) -> -> exml:element(). result(MamNs, QueryID, MessageUID, Children) when is_list(Children) -> %% + Attrs = case QueryID =/= undefined andalso QueryID =/= <<>> of + true-> + #{<<"queryid">> => QueryID}; + false -> + #{} + end, #xmlel{ name = <<"result">>, - attrs = [{<<"queryid">>, QueryID} || QueryID =/= undefined, QueryID =/= <<>>] ++ - [{<<"xmlns">>, MamNs}, - {<<"id">>, MessageUID}], + attrs = Attrs#{<<"xmlns">> => MamNs, <<"id">> => MessageUID}, children = Children}. @@ -551,12 +560,12 @@ result_set(FirstId, LastId, undefined, undefined) || LastId =/= undefined], #xmlel{ name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = FirstEl ++ LastEl}; result_set(FirstId, LastId, FirstIndexI, CountI) when ?MAYBE_BIN(FirstId), ?MAYBE_BIN(LastId) -> FirstEl = [#xmlel{name = <<"first">>, - attrs = [{<<"index">>, integer_to_binary(FirstIndexI)}], + attrs = #{<<"index">> => integer_to_binary(FirstIndexI)}, children = [#xmlcdata{content = FirstId}] } || FirstId =/= undefined], @@ -569,7 +578,7 @@ result_set(FirstId, LastId, FirstIndexI, CountI) children = [#xmlcdata{content = integer_to_binary(CountI)}]}, #xmlel{ name = <<"set">>, - attrs = [{<<"xmlns">>, ?NS_RSM}], + attrs = #{<<"xmlns">> => ?NS_RSM}, children = FirstEl ++ LastEl ++ [CountEl]}. @@ -577,7 +586,7 @@ result_set(FirstId, LastId, FirstIndexI, CountI) result_query(SetEl, Namespace) -> #xmlel{ name = <<"query">>, - attrs = [{<<"xmlns">>, Namespace}], + attrs = #{<<"xmlns">> => Namespace}, children = [SetEl]}. -spec result_prefs(DefaultMode :: archive_behaviour(), @@ -591,8 +600,8 @@ result_prefs(DefaultMode, AlwaysJIDs, NeverJIDs, Namespace) -> children = encode_jids(NeverJIDs)}, #xmlel{ name = <<"prefs">>, - attrs = [{<<"xmlns">>, Namespace}, - {<<"default">>, atom_to_binary(DefaultMode, utf8)}], + attrs = #{<<"xmlns">> => Namespace, + <<"default">> => atom_to_binary(DefaultMode, utf8)}, children = [AlwaysEl, NeverEl] }. @@ -613,11 +622,15 @@ encode_jids(JIDs) -> module()) -> exml:element(). make_fin_element(HostType, Params, MamNs, IsComplete, IsStable, ResultSetEl, ExtFinMod) -> + Attrs0 = if IsComplete -> #{<<"complete">> => <<"true">>}; + true -> #{} + end, + Attrs1 = if IsStable -> Attrs0; + true -> Attrs0#{<<"stable">> => <<"false">>} + end, FinEl = #xmlel{ name = <<"fin">>, - attrs = [{<<"xmlns">>, MamNs}] - ++ [{<<"complete">>, <<"true">>} || IsComplete] - ++ [{<<"stable">>, <<"false">>} || not IsStable], + attrs = Attrs1#{<<"xmlns">> => MamNs}, children = [ResultSetEl]}, maybe_transform_fin_elem(ExtFinMod, HostType, Params, FinEl). @@ -630,17 +643,17 @@ maybe_transform_fin_elem(Module, HostType, Params, FinEl) -> make_metadata_element() -> #xmlel{ name = <<"metadata">>, - attrs = [{<<"xmlns">>, ?NS_MAM_06}]}. + attrs = #{<<"xmlns">> => ?NS_MAM_06}}. -spec make_metadata_element(binary(), binary(), binary(), binary()) -> exml:element(). make_metadata_element(FirstMsgID, FirstMsgTS, LastMsgID, LastMsgTS) -> #xmlel{ name = <<"metadata">>, - attrs = [{<<"xmlns">>, ?NS_MAM_06}], + attrs = #{<<"xmlns">> => ?NS_MAM_06}, children = [#xmlel{name = <<"start">>, - attrs = [{<<"id">>, FirstMsgID}, {<<"timestamp">>, FirstMsgTS}]}, + attrs = #{<<"id">> => FirstMsgID, <<"timestamp">> => FirstMsgTS}}, #xmlel{name = <<"end">>, - attrs = [{<<"id">>, LastMsgID}, {<<"timestamp">>, LastMsgTS}]}] + attrs = #{<<"id">> => LastMsgID, <<"timestamp">> => LastMsgTS}}] }. -spec parse_prefs(PrefsEl :: exml:element()) -> mod_mam:preference(). diff --git a/src/mod_amp.erl b/src/mod_amp.erl index 1098b0c05ab..f3aeb2add32 100644 --- a/src/mod_amp.erl +++ b/src/mod_amp.erl @@ -23,7 +23,7 @@ -include("jlib.hrl"). -define(AMP_FEATURE, - #xmlel{name = <<"amp">>, attrs = [{<<"xmlns">>, ?NS_AMP_FEATURE}]}). + #xmlel{name = <<"amp">>, attrs = #{<<"xmlns">> => ?NS_AMP_FEATURE}}). -spec start(mongooseim:host_type(), gen_mod:module_opts()) -> ok. start(HostType, _Opts) -> diff --git a/src/mod_auth_token.erl b/src/mod_auth_token.erl index e9d28ec3ea9..232076bc51a 100644 --- a/src/mod_auth_token.erl +++ b/src/mod_auth_token.erl @@ -297,7 +297,7 @@ create_token_response(Acc, From, IQ) -> {#token{} = AccessToken, #token{} = RefreshToken} -> IQ#iq{type = result, sub_el = [#xmlel{name = <<"items">>, - attrs = [{<<"xmlns">>, ?NS_ESL_TOKEN_AUTH}], + attrs = #{<<"xmlns">> => ?NS_ESL_TOKEN_AUTH}, children = [token_to_xmlel(AccessToken), token_to_xmlel(RefreshToken)]}]}; {_, _} -> {error, mongoose_xmpp_errors:internal_server_error()} @@ -356,7 +356,7 @@ token_to_xmlel(#token{type = Type} = T) -> access -> <<"access_token">>; refresh -> <<"refresh_token">> end, - attrs = [{<<"xmlns">>, ?NS_ESL_TOKEN_AUTH}], + attrs = #{<<"xmlns">> => ?NS_ESL_TOKEN_AUTH}, children = [#xmlcdata{content = base64:encode(serialize(T))}]}. %% args: Token with Mac decoded from transport, #token diff --git a/src/mod_bind2.erl b/src/mod_bind2.erl index a5aa951930e..070a3ce4003 100644 --- a/src/mod_bind2.erl +++ b/src/mod_bind2.erl @@ -16,7 +16,7 @@ -include("jlib.hrl"). --define(XMLNS_BIND_2, {<<"xmlns">>, ?NS_BIND_2}). +-define(XMLNS_BIND_2, #{<<"xmlns">> => ?NS_BIND_2}). -behaviour(gen_mod). @@ -121,7 +121,7 @@ bind2_failed(SaslAcc) -> {ok, mod_sasl2:update_inline_request(SaslAcc, ?MODULE, Error, failure)}. create_bind_response(Answer) -> - #xmlel{name = Answer, attrs = [?XMLNS_BIND_2]}. + #xmlel{name = Answer, attrs = ?XMLNS_BIND_2}. %% Helpers -spec generate_lresource(exml:element()) -> jid:lresource(). @@ -146,7 +146,7 @@ feature(C2SData) -> Inlines = mongoose_hooks:bind2_stream_features(C2SData, []), InlineElem = inlines(Inlines), #xmlel{name = feature_name(), - attrs = [?XMLNS_BIND_2], + attrs = ?XMLNS_BIND_2, children = [InlineElem]}. -spec inlines([exml:element()]) -> exml:element(). diff --git a/src/mod_bosh.erl b/src/mod_bosh.erl index 731465c20b3..8f7c542ba58 100644 --- a/src/mod_bosh.erl +++ b/src/mod_bosh.erl @@ -432,9 +432,9 @@ terminal_condition(Condition, Details, Req) -> -spec terminal_condition_body(binary(), [exml:element()]) -> binary(). terminal_condition_body(Condition, Children) -> exml:to_binary(#xmlel{name = <<"body">>, - attrs = [{<<"type">>, <<"terminate">>}, - {<<"condition">>, Condition}, - {<<"xmlns">>, ?NS_HTTPBIND}], + attrs = #{<<"type">> => <<"terminate">>, + <<"condition">> => Condition, + <<"xmlns">> => ?NS_HTTPBIND}, children = Children}). %%-------------------------------------------------------------------- @@ -481,7 +481,10 @@ set_max_hold(Body) -> maybe_set_max_hold(1, Body) -> {ok, Body}; maybe_set_max_hold(ClientHold, #xmlel{attrs = Attrs} = Body) when ClientHold > 1 -> - NewAttrs = lists:keyreplace(<<"hold">>, 1, Attrs, {<<"hold">>, <<"1">>}), + NewAttrs = case Attrs of + #{<<"hold">> := _} -> Attrs#{<<"hold">> => <<"1">>}; + _ -> Attrs + end, {ok, Body#xmlel{attrs = NewAttrs}}; maybe_set_max_hold(_, _) -> {error, invalid_hold}. diff --git a/src/mod_bosh_socket.erl b/src/mod_bosh_socket.erl index aefd96413dc..34f37daad29 100644 --- a/src/mod_bosh_socket.erl +++ b/src/mod_bosh_socket.erl @@ -84,7 +84,7 @@ inactivity :: pos_integer() | infinity, inactivity_tref :: reference() | 'undefined', %% Max pause period in seconds. - max_pause :: pos_integer(), + max_pause :: pos_integer() | undefined, max_wait :: pos_integer() | infinity, %% Are acknowledgements used? server_acks :: boolean(), @@ -722,23 +722,23 @@ send_wrapped_to_handler(Pid, Wrapped, State) -> State. --spec maybe_ack(rid(), state()) -> [{binary(), _}]. -maybe_ack(HandlerRid, #state{rid = Rid} = S) -> +-spec maybe_add_ack(rid(), state(), exml:attrs()) -> exml:attrs(). +maybe_add_ack(HandlerRid, #state{rid = Rid} = S, Attrs) -> case Rid > HandlerRid of true -> - server_ack(S#state.server_acks, Rid); + server_ack(S#state.server_acks, Rid, Attrs); false -> - [] + Attrs end. --spec maybe_report(state()) -> {[{binary(), _}], state()}. -maybe_report(#state{report = false} = S) -> - {[], S}; -maybe_report(#state{report = Report} = S) -> +-spec maybe_add_report(state(), exml:attrs()) -> {exml:attrs(), state()}. +maybe_add_report(#state{report = false} = S, Attrs) -> + {Attrs, S}; +maybe_add_report(#state{report = Report} = S, Attrs) -> {ReportRid, ElapsedTime} = Report, - NewAttrs = [{<<"report">>, integer_to_binary(ReportRid)}, - {<<"time">>, integer_to_binary(ElapsedTime)}], + NewAttrs = Attrs#{<<"report">> => integer_to_binary(ReportRid), + <<"time">> => integer_to_binary(ElapsedTime)}, {NewAttrs, S#state{report = false}}. @@ -899,12 +899,12 @@ get_attr(Attr, Element, Default) -> -spec stream_start(binary(), binary()) -> exml_stream:start(). stream_start(From, To) -> #xmlstreamstart{name = <<"stream:stream">>, - attrs = [{<<"from">>, From}, - {<<"to">>, To}, - {<<"version">>, <<"1.0">>}, - {<<"xml:lang">>, <<"en">>}, - {<<"xmlns">>, ?NS_CLIENT}, - {<<"xmlns:stream">>, ?NS_STREAM}]}. + attrs = #{<<"from">> => From, + <<"to">> => To, + <<"version">> => <<"1.0">>, + <<"xml:lang">> => <<"en">>, + <<"xmlns">> => ?NS_CLIENT, + <<"xmlns:stream">> => ?NS_STREAM}}. -spec bosh_wrap([any()], rid(), state()) -> {exml:element(), state()}. @@ -928,12 +928,11 @@ bosh_wrap(Elements, Rid, #state{} = S) -> {{bosh_body(S), Stanzas}, S#state{pending = Pending ++ [StreamEnd]}} end, - MaybeAck = maybe_ack(Rid, NS), - {MaybeReport, NNS} = maybe_report(NS), + Attrs1 = maybe_add_ack(Rid, NS, Body#xmlel.attrs), + {Attrs2, NNS} = maybe_add_report(NS, Attrs1), HasStreamPrefix = (exml_query:attr(Body, <<"xmlns:stream">>) /= undefined), - MaybeStreamPrefix = maybe_stream_prefix(HasStreamPrefix, Children), - ExtraAttrs = MaybeAck ++ MaybeReport ++ MaybeStreamPrefix, - {Body#xmlel{attrs = Body#xmlel.attrs ++ ExtraAttrs, + Attrs3 = maybe_add_stream_prefix(HasStreamPrefix, Children, Attrs2), + {Body#xmlel{attrs = Attrs3, children = maybe_add_default_ns_to_children(Children)}, NNS}. @@ -949,67 +948,73 @@ is_stream_event(_) -> %% @doc Bosh body for a session creation response. -spec bosh_stream_start_body(exml_stream:start(), state()) -> exml:element(). bosh_stream_start_body(#xmlstreamstart{attrs = Attrs}, #state{} = S) -> - #xmlel{name = <<"body">>, - attrs = [{<<"wait">>, integer_to_binary(S#state.wait)}, - {<<"requests">>, - integer_to_binary(?CONCURRENT_REQUESTS)}, - {<<"hold">>, integer_to_binary(S#state.hold)}, - {<<"from">>, proplists:get_value(<<"from">>, Attrs)}, - %% TODO: how to support these with cowboy? - {<<"accept">>, <<"deflate, gzip">>}, - {<<"sid">>, S#state.sid}, - {<<"xmpp:restartlogic">>, <<"true">>}, - {<<"xmpp:version">>, <<"1.0">>}, - {<<"xmlns">>, ?NS_HTTPBIND}, - {<<"xmlns:xmpp">>, <<"urn:xmpp:xbosh">>}, - {<<"xmlns:stream">>, ?NS_STREAM}] ++ - inactivity(S#state.inactivity) ++ - maxpause(S#state.max_pause) ++ - %% TODO: shouldn't an ack be sent on restart? - server_ack(S#state.server_acks, S#state.rid), - children = []}. + Attrs1 = #{<<"wait">> => integer_to_binary(S#state.wait), + <<"requests">> => integer_to_binary(?CONCURRENT_REQUESTS), + <<"hold">> => integer_to_binary(S#state.hold), + <<"from">> => maps:get(<<"from">>, Attrs,undefined), + % TODO: how to support these with cowbo? + <<"accept">> => <<"deflate, gzip">>, + <<"sid">> => S#state.sid, + <<"xmpp:restartlogic">> => <<"true">>, + <<"xmpp:version">> => <<"1.0">>, + <<"xmlns">> => ?NS_HTTPBIND, + <<"xmlns:xmpp">> => <<"urn:xmpp:xbosh">>, + <<"xmlns:stream">> => ?NS_STREAM}, + + Attrs2 = inactivity(S#state.inactivity, Attrs1), + Attrs3 = maxpause(S#state.max_pause, Attrs2), + + %% TODO: shouldn't an ack be sent on restart? + Attrs4 = server_ack(S#state.server_acks, S#state.rid, Attrs3), + #xmlel{name = <<"body">>, attrs = Attrs4, children = []}. --spec inactivity('infinity' | 'undefined' | pos_integer()) -> [{binary(), _}]. -inactivity(I) -> - [{<<"inactivity">>, integer_to_binary(I)} || is_integer(I)]. +-spec inactivity('infinity' | 'undefined' | pos_integer(), exml:attrs()) -> exml:attrs(). +inactivity(I, Attrs) when is_integer(I)-> + Attrs#{<<"inactivity">> => integer_to_binary(I)}; +inactivity(_, Attrs) -> + Attrs. --spec maxpause('undefined' | pos_integer()) -> [{binary(), _}]. -maxpause(MP) -> - [{<<"maxpause">>, integer_to_binary(MP)} || is_integer(MP)]. +-spec maxpause('undefined' | pos_integer(), exml:attrs()) -> exml:attrs(). +maxpause(MP, Attrs) when is_integer(MP)-> + Attrs#{<<"maxpause">> => integer_to_binary(MP)}; +maxpause(_MP, Attrs)-> + Attrs. --spec server_ack('false' | 'true' | 'undefined', 'undefined' | rid()) - -> [{binary(), _}]. -server_ack(ServerAcks, Rid) -> - [{<<"ack">>, integer_to_binary(Rid)} || ServerAcks =:= true]. +-spec server_ack('false' | 'true' | 'undefined', 'undefined' | rid(), exml:attrs()) + -> exml:attrs(). +server_ack(true, Rid, Attrs) -> + Attrs#{<<"ack">> => integer_to_binary(Rid)}; +server_ack(_, _, Attrs) -> + Attrs. %% @doc Bosh body for an ordinary stream element(s). -spec bosh_body(state()) -> exml:element(). bosh_body(#state{} = S) -> #xmlel{name = <<"body">>, - attrs = [{<<"sid">>, S#state.sid}, - {<<"xmlns">>, ?NS_HTTPBIND}], + attrs = #{<<"sid">> => S#state.sid, + <<"xmlns">> => ?NS_HTTPBIND}, children = []}. -spec bosh_stream_end_body() -> exml:element(). bosh_stream_end_body() -> #xmlel{name = <<"body">>, - attrs = [{<<"type">>, <<"terminate">>}, - {<<"xmlns">>, ?NS_HTTPBIND}], + attrs = #{<<"type">> => <<"terminate">>, + <<"xmlns">> => ?NS_HTTPBIND}, children = []}. -maybe_stream_prefix(true, _) -> - []; -maybe_stream_prefix(_, Stanzas) -> +maybe_add_stream_prefix(true, _, Attrs) -> + Attrs; +maybe_add_stream_prefix(_, Stanzas, Attrs) -> case lists:any(fun is_stream_prefix/1, Stanzas) of false -> - []; + Attrs; true -> - [{<<"xmlns:stream">>, ?NS_STREAM}] + Attrs#{<<"xmlns:stream">> => ?NS_STREAM} end. is_stream_prefix(#xmlel{name = <<"stream:error">>}) -> true; @@ -1028,7 +1033,7 @@ maybe_add_default_ns(#xmlel{name = Name, attrs = Attrs} = El) when Name =:= <<"message">>; Name =:= <<"presence">>; Name =:= <<"iq">> -> case exml_query:attr(El, <<"xmlns">>) of undefined -> - El#xmlel{attrs = [{<<"xmlns">>, ?NS_CLIENT} | Attrs]}; + El#xmlel{attrs = Attrs#{<<"xmlns">> => ?NS_CLIENT}}; _ -> El end; diff --git a/src/mod_caps.erl b/src/mod_caps.erl index ca973e317cf..97264a150ba 100644 --- a/src/mod_caps.erl +++ b/src/mod_caps.erl @@ -197,8 +197,10 @@ caps_stream_features(Acc, #{lserver := LServer}, #{host_type := HostType}) -> Acc; Hash -> [#xmlel{name = <<"c">>, - attrs = [{<<"xmlns">>, ?NS_CAPS}, {<<"hash">>, <<"sha-1">>}, - {<<"node">>, ?MONGOOSE_URI}, {<<"ver">>, Hash}], + attrs = #{<<"xmlns">> => ?NS_CAPS, + <<"hash">> => <<"sha-1">>, + <<"node">> => ?MONGOOSE_URI, + <<"ver">> => Hash}, children = []} | Acc] end, @@ -431,10 +433,8 @@ feature_request(Acc, LServer, From, Caps, [SubNode | Tail] = SubNodes) -> sub_el = [#xmlel{name = <<"query">>, attrs = - [{<<"xmlns">>, ?NS_DISCO_INFO}, - {<<"node">>, - <>}], + #{<<"xmlns">> => ?NS_DISCO_INFO, + <<"node">> => <>}, children = []}]}, cache_tab:insert(caps_features, NodePair, os:system_time(second), caps_write_fun(HostType, NodePair, os:system_time(second))), diff --git a/src/mod_carboncopy.erl b/src/mod_carboncopy.erl index f5b55d33afb..7fe5e83eb47 100644 --- a/src/mod_carboncopy.erl +++ b/src/mod_carboncopy.erl @@ -110,7 +110,7 @@ disco_local_features(Acc, _, _) -> -spec bind2_stream_features(Acc, #{c2s_data := mongoose_c2s:data()}, gen_hook:extra()) -> {ok, Acc} when Acc :: [exml:element()]. bind2_stream_features(Acc, _, _) -> - SmFeature = #xmlel{name = <<"feature">>, attrs = [{<<"var">>, ?NS_CC_2}]}, + SmFeature = #xmlel{name = <<"feature">>, attrs = #{<<"var">> => ?NS_CC_2}}, {ok, [SmFeature | Acc]}. -spec bind2_enable_features(SaslAcc, mod_sasl2:c2s_state_data(), gen_hook:extra()) -> @@ -333,23 +333,23 @@ build_forward_packet(Acc, JID, Packet, Sender, Dest, Direction, Version) -> % The wrapping message SHOULD maintain the same 'type' attribute value; Type = exml_query:attr(Packet, <<"type">>, <<"normal">>), #xmlel{name = <<"message">>, - attrs = [{<<"xmlns">>, <<"jabber:client">>}, - {<<"type">>, Type}, - {<<"from">>, jid:to_binary(Sender)}, - {<<"to">>, jid:to_binary(Dest)}], + attrs = #{<<"xmlns">> => <<"jabber:client">>, + <<"type">> => Type, + <<"from">> => jid:to_binary(Sender), + <<"to">> => jid:to_binary(Dest)}, children = carbon_copy_children(Acc, Version, JID, Packet, Direction)}. carbon_copy_children(Acc, ?NS_CC_1, JID, Packet, Direction) -> [ #xmlel{name = atom_to_binary(Direction, utf8), - attrs = [{<<"xmlns">>, ?NS_CC_1}]}, + attrs = #{<<"xmlns">> => ?NS_CC_1}}, #xmlel{name = <<"forwarded">>, - attrs = [{<<"xmlns">>, ?NS_FORWARD}], + attrs = #{<<"xmlns">> => ?NS_FORWARD}, children = [complete_packet(Acc, JID, Packet, Direction)]} ]; carbon_copy_children(Acc, ?NS_CC_2, JID, Packet, Direction) -> [ #xmlel{name = atom_to_binary(Direction, utf8), - attrs = [{<<"xmlns">>, ?NS_CC_2}], + attrs = #{<<"xmlns">> => ?NS_CC_2}, children = [ #xmlel{name = <<"forwarded">>, - attrs = [{<<"xmlns">>, ?NS_FORWARD}], + attrs = #{<<"xmlns">> => ?NS_FORWARD}, children = [complete_packet(Acc, JID, Packet, Direction)]} ]} ]. enable(JID, CC, Acc) -> @@ -367,17 +367,17 @@ disable(JID, Acc) -> complete_packet(Acc, From, #xmlel{name = <<"message">>, attrs = OrigAttrs} = Packet, sent) -> %% if this is a packet sent by user on this host, then Packet doesn't %% include the 'from' attribute. We must add it. - Attrs = lists:keystore(<<"xmlns">>, 1, OrigAttrs, {<<"xmlns">>, <<"jabber:client">>}), + Attrs = OrigAttrs#{<<"xmlns">> => <<"jabber:client">>}, Packet2 = set_stanza_id(Acc, From, Packet), - case proplists:get_value(<<"from">>, Attrs) of - undefined -> - Packet2#xmlel{attrs = [{<<"from">>, jid:to_binary(From)} | Attrs]}; + case is_map_key(<<"from">>, Attrs) of + false -> + Packet2#xmlel{attrs = Attrs#{<<"from">> => jid:to_binary(From)}}; _ -> Packet2#xmlel{attrs = Attrs} end; complete_packet(_Acc, _From, #xmlel{name = <<"message">>, attrs = OrigAttrs} = Packet, received) -> - Attrs = lists:keystore(<<"xmlns">>, 1, OrigAttrs, {<<"xmlns">>, <<"jabber:client">>}), + Attrs = OrigAttrs#{<<"xmlns">> => <<"jabber:client">>}, Packet#xmlel{attrs = Attrs}. get_cc_enabled_resources(JID) -> diff --git a/src/mod_csi.erl b/src/mod_csi.erl index f6b1ba00cf3..68d287c4e30 100644 --- a/src/mod_csi.erl +++ b/src/mod_csi.erl @@ -80,7 +80,7 @@ c2s_stream_features(Acc, _, _) -> -spec bind2_stream_features(Acc, #{c2s_data := mongoose_c2s:data()}, gen_hook:extra()) -> {ok, Acc} when Acc :: [exml:element()]. bind2_stream_features(Acc, _, _) -> - SmFeature = #xmlel{name = <<"feature">>, attrs = [{<<"var">>, ?NS_CSI}]}, + SmFeature = #xmlel{name = <<"feature">>, attrs = #{<<"var">> => ?NS_CSI}}, {ok, [SmFeature | Acc]}. -spec bind2_enable_features(SaslAcc, mod_sasl2:c2s_state_data(), gen_hook:extra()) -> @@ -213,7 +213,7 @@ handle_active_request(Acc, #{c2s_data := C2SData}) -> -spec csi() -> exml:element(). csi() -> - #xmlel{name = <<"csi">>, attrs = [{<<"xmlns">>, ?NS_CSI}]}. + #xmlel{name = <<"csi">>, attrs = #{<<"xmlns">> => ?NS_CSI}}. -spec mark_acc_as_buffered(mongoose_acc:t()) -> mongoose_acc:t(). mark_acc_as_buffered(Acc) -> diff --git a/src/mod_disco.erl b/src/mod_disco.erl index af833801273..1c58b92df17 100644 --- a/src/mod_disco.erl +++ b/src/mod_disco.erl @@ -350,15 +350,15 @@ get_user_resources(JID = #jid{luser = LUser}) -> -spec make_iq_result(jlib:iq(), binary(), binary(), [exml:element()]) -> jlib:iq(). make_iq_result(IQ, NameSpace, Node, ChildrenXML) -> + Attrs = make_node_attrs(Node), IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, NameSpace} | make_node_attrs(Node)], - children = ChildrenXML - }]}. + attrs = Attrs#{<<"xmlns">> => NameSpace}, + children = ChildrenXML}]}. --spec make_node_attrs(Node :: binary()) -> [{binary(), binary()}]. -make_node_attrs(<<>>) -> []; -make_node_attrs(Node) -> [{<<"node">>, Node}]. +-spec make_node_attrs(Node :: binary()) -> exml:attrs(). +make_node_attrs(<<>>) -> #{}; +make_node_attrs(Node) -> #{<<"node">> => Node}. -spec server_info_to_field(server_info()) -> mongoose_disco:info_field(). server_info_to_field(#{name := Name, urls := URLs}) -> diff --git a/src/mod_extdisco.erl b/src/mod_extdisco.erl index 9d201501e8e..fa7394091c3 100644 --- a/src/mod_extdisco.erl +++ b/src/mod_extdisco.erl @@ -108,18 +108,19 @@ request_type(_) -> create_iq_response(Services) -> #xmlel{name = <<"services">>, - attrs = [{<<"xmlns">>, ?NS_EXTDISCO}], - children = prepare_services_element(Services)}. + attrs = #{<<"xmlns">> => ?NS_EXTDISCO}, + children = prepare_services_element(Services)}. create_iq_response_services(Services, Type) -> #xmlel{name = <<"services">>, - attrs = [{<<"xmlns">>, ?NS_EXTDISCO}, {<<"type">>, atom_to_binary(Type, utf8)}], - children = prepare_services_element(Services)}. + attrs = #{<<"xmlns">> => ?NS_EXTDISCO, + <<"type">> => atom_to_binary(Type, utf8)}, + children = prepare_services_element(Services)}. create_iq_response_credentials(Services) -> #xmlel{name = <<"credentials">>, - attrs = [{<<"xmlns">>, ?NS_EXTDISCO}], - children = prepare_services_element(Services)}. + attrs = #{<<"xmlns">> => ?NS_EXTDISCO}, + children = prepare_services_element(Services)}. get_external_services(HostType) -> gen_mod:get_module_opt(HostType, ?MODULE, service). @@ -131,7 +132,7 @@ prepare_services_element(Services) -> [#xmlel{name = <<"service">>, attrs = make_attrs(Service)} || Service <- Services]. make_attrs(Service) -> - [{atom_to_binary(Key), format_value(Key, Value)} || {Key, Value} <- maps:to_list(Service)]. + #{atom_to_binary(Key) => format_value(Key, Value) || Key := Value <- Service}. format_value(port, Port) -> integer_to_binary(Port); format_value(type, Type) -> atom_to_binary(Type); diff --git a/src/mod_last.erl b/src/mod_last.erl index a92accb4c55..2109562dd9e 100644 --- a/src/mod_last.erl +++ b/src/mod_last.erl @@ -134,10 +134,8 @@ process_local_iq(Acc, _From, _To, #iq{type = Type, sub_el = SubEl} = IQ, _Extra) {Acc, IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, ?NS_LAST}, - {<<"seconds">>, - integer_to_binary(Sec)}], + attrs = #{<<"xmlns">> => ?NS_LAST, + <<"seconds">> => integer_to_binary(Sec)}, children = []}]}} end. @@ -196,20 +194,16 @@ make_response(HostType, IQ, SubEl, JID, allow) -> IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, ?NS_LAST}, - {<<"seconds">>, - integer_to_binary(Sec)}], - children = [{xmlcdata, Status}]}]} + attrs = #{<<"xmlns">> => ?NS_LAST, + <<"seconds">> => integer_to_binary(Sec)}, + children = [#xmlcdata{content = Status}]}]} end; _ -> IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = - [{<<"xmlns">>, ?NS_LAST}, - {<<"seconds">>, <<"0">>}], - children = []}]} + attrs = #{<<"xmlns">> => ?NS_LAST, + <<"seconds">> => <<"0">>}}]} end. -spec get_last_info(mongooseim:host_type(), jid:luser(), jid:lserver()) diff --git a/src/mod_ping.erl b/src/mod_ping.erl index 0a57b9c3251..312934446fd 100644 --- a/src/mod_ping.erl +++ b/src/mod_ping.erl @@ -233,8 +233,8 @@ user_ping_response(Acc, #{time_delta := TDelta, jid := Jid}, #{host_type := Host -spec ping_get(binary()) -> exml:element(). ping_get(Id) -> #xmlel{name = <<"iq">>, - attrs = [{<<"type">>, <<"get">>}, {<<"id">>, Id}], - children = [#xmlel{name = <<"ping">>, attrs = [{<<"xmlns">>, ?NS_PING}]}]}. + attrs = #{<<"type">> => <<"get">>, <<"id">> => Id}, + children = [#xmlel{name = <<"ping">>, attrs = #{<<"xmlns">> => ?NS_PING}}]}. -spec is_ping_error(exml:element()) -> boolean(). is_ping_error(Stanza) -> diff --git a/src/mod_presence.erl b/src/mod_presence.erl index 33497a69ed5..f5d16132487 100644 --- a/src/mod_presence.erl +++ b/src/mod_presence.erl @@ -539,7 +539,7 @@ create_route_accs(Acc0, To, List) when is_list(List) -> -spec presence_probe() -> exml:element(). presence_probe() -> #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, <<"probe">>}]}. + attrs = #{<<"type">> => <<"probe">>}}. -spec presence_unavailable_stanza() -> exml:element(). presence_unavailable_stanza() -> @@ -548,12 +548,12 @@ presence_unavailable_stanza() -> -spec presence_unavailable_stanza(binary()) -> exml:element(). presence_unavailable_stanza(<<>>) -> #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, <<"unavailable">>}]}; + attrs = #{<<"type">> => <<"unavailable">>}}; presence_unavailable_stanza(Status) -> StatusEl = #xmlel{name = <<"status">>, children = [#xmlcdata{content = Status}]}, #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, <<"unavailable">>}], + attrs = #{<<"type">> => <<"unavailable">>}, children = [StatusEl]}. close_session_status(normal) -> diff --git a/src/mod_private_api.erl b/src/mod_private_api.erl index a260966eeaf..b0a782cf73a 100644 --- a/src/mod_private_api.erl +++ b/src/mod_private_api.erl @@ -31,17 +31,17 @@ private_set(#jid{lserver = Domain} = JID, Xml) -> do_private_get(JID, Element, Ns) -> {ok, HostType} = mongoose_domain_api:get_domain_host_type(JID#jid.lserver), - Xml = #xmlel{ name = Element, attrs = [{<<"xmlns">>, Ns}]}, + Xml = #xmlel{ name = Element, attrs = #{<<"xmlns">> => Ns}}, {_, ResIq} = send_iq(get, Xml, JID, HostType), [#xmlel{ name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_PRIVATE}], + attrs = #{<<"xmlns">> := ?NS_PRIVATE}, children = [SubEl] }] = ResIq#iq.sub_el, {ok, SubEl}. send_iq(Method, Xml, From = To = _JID, HostType) -> IQ = {iq, <<>>, Method, ?NS_PRIVATE, <<>>, #xmlel{ name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_PRIVATE}], + attrs = #{<<"xmlns">> => ?NS_PRIVATE}, children = [Xml] } }, Acc = mongoose_acc:new(#{ location => ?LOCATION, from_jid => From, diff --git a/src/mod_register.erl b/src/mod_register.erl index e5cf74bc6b5..04dd69dfdaf 100644 --- a/src/mod_register.erl +++ b/src/mod_register.erl @@ -139,7 +139,7 @@ process_welcome_message(#{subject := Subject, body := Body}) -> Extra :: gen_hook:extra(). c2s_stream_features(Acc, _, _) -> NewAcc = [#xmlel{name = <<"register">>, - attrs = [{<<"xmlns">>, ?NS_FEATURE_IQREGISTER}]} | Acc], + attrs = #{<<"xmlns">> => ?NS_FEATURE_IQREGISTER}} | Acc], {ok, NewAcc}. -spec user_send_xmlel(mongoose_acc:t(), mongoose_c2s_hooks:params(), gen_hook:extra()) -> @@ -306,7 +306,7 @@ process_iq_get(_HostType, From, _To, #iq{lang = Lang, sub_el = Child} = IQ, _Sou Lang, <<"Choose a username and password to register with this server">>), IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, <<"jabber:iq:register">>}], + attrs = #{<<"xmlns">> => <<"jabber:iq:register">>}, children = [#xmlel{name = <<"instructions">>, children = [#xmlcdata{content = TranslatedMsg}]}, #xmlel{name = <<"username">>, @@ -399,7 +399,7 @@ send_welcome_message(HostType, #jid{lserver = Server} = JID) -> ejabberd_router:route( jid:make_noprep(<<>>, Server, <<>>), JID, - #xmlel{name = <<"message">>, attrs = [{<<"type">>, <<"normal">>}], + #xmlel{name = <<"message">>, attrs = #{<<"type">> => <<"normal">>}, children = [#xmlel{name = <<"subject">>, children = [#xmlcdata{content = Subj}]}, #xmlel{name = <<"body">>, @@ -426,7 +426,7 @@ send_registration_notification(JIDBin, Domain, Body) -> error -> ok; JID -> Message = #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"chat">>}], + attrs = #{<<"type">> => <<"chat">>}, children = [#xmlel{name = <<"body">>, children = [#xmlcdata{content = Body}]}]}, ejabberd_router:route(jid:make_noprep(<<>>, Domain, <<>>), JID, Message) @@ -535,7 +535,7 @@ ip_to_integer({IP1, IP2, IP3, IP4, IP5, IP6, IP7, IP8}) -> X. set_sender(#xmlel{attrs = A} = Stanza, #jid{} = From) -> - Stanza#xmlel{attrs = [{<<"from">>, jid:to_binary(From)}|A]}. + Stanza#xmlel{attrs = A#{<<"from">> => jid:to_binary(From)}}. is_query_element(#xmlel{name = <<"query">>}) -> true; diff --git a/src/mod_sasl2.erl b/src/mod_sasl2.erl index b48c6ddb384..4765d2ba451 100644 --- a/src/mod_sasl2.erl +++ b/src/mod_sasl2.erl @@ -17,8 +17,8 @@ -include("mongoose_logger.hrl"). -define(BIND_RETRIES, 3). --define(XMLNS_SASL, {<<"xmlns">>, ?NS_SASL}). --define(XMLNS_SASL_2, {<<"xmlns">>, ?NS_SASL_2}). +-define(XMLNS_SASL, #{<<"xmlns">> => ?NS_SASL}). +-define(XMLNS_SASL_2, #{<<"xmlns">> => ?NS_SASL_2}). -behaviour(gen_mod). -behaviour(gen_statem). @@ -125,7 +125,7 @@ c2s_stream_features(Acc, #{c2s_data := C2SData}, _) -> andalso lists:keyfind(<<"mechanisms">>, #xmlel.name, Acc) of false -> {ok, Acc}; - #xmlel{attrs = [?XMLNS_SASL], children = Mechanisms} -> + #xmlel{attrs = #{<<"xmlns">> := ?NS_SASL}, children = Mechanisms} -> Sasl2Feature = feature(C2SData, Mechanisms), {ok, lists:keystore(feature_name(), #xmlel.name, Acc, Sasl2Feature)} end. @@ -370,12 +370,12 @@ challenge_stanza(ServerOut) -> -spec failure_stanza(binary()) -> exml:element(). failure_stanza(Reason) -> - SaslErrorCode = #xmlel{name = Reason, attrs = [?XMLNS_SASL]}, + SaslErrorCode = #xmlel{name = Reason, attrs = ?XMLNS_SASL}, sasl2_ns_stanza(<<"failure">>, [SaslErrorCode]). -spec sasl2_ns_stanza(binary(), [exml:element() | exml:cdata()]) -> exml:element(). sasl2_ns_stanza(Name, Children) -> - #xmlel{name = Name, attrs = [?XMLNS_SASL_2], children = Children}. + #xmlel{name = Name, attrs = ?XMLNS_SASL_2, children = Children}. -spec success_subelement(binary(), binary()) -> exml:element(). success_subelement(Name, AuthId) -> @@ -423,7 +423,7 @@ feature(C2SData, Mechanisms) -> InlineFeatures = mongoose_hooks:sasl2_stream_features(C2SData, []), InlineElem = inlines(InlineFeatures), #xmlel{name = feature_name(), - attrs = [?XMLNS_SASL_2], + attrs = ?XMLNS_SASL_2, children = [InlineElem | Mechanisms]}. -spec inlines([exml:element()]) -> exml:element(). diff --git a/src/mod_time.erl b/src/mod_time.erl index 01d0704f486..add1f582b44 100644 --- a/src/mod_time.erl +++ b/src/mod_time.erl @@ -52,11 +52,11 @@ process_local_iq(Acc, _From, _To, #iq{type = get} = IQ, _Extra) -> R = IQ#iq{type = result, sub_el = [#xmlel{name = <<"time">>, - attrs = [{<<"xmlns">>, ?NS_TIME}], + attrs = #{<<"xmlns">> => ?NS_TIME}, children = - [#xmlel{name = <<"tzo">>, attrs = [], + [#xmlel{name = <<"tzo">>, children = [#xmlcdata{content = list_to_binary(TZODiff)}]}, - #xmlel{name = <<"utc">>, attrs = [], + #xmlel{name = <<"utc">>, children = [#xmlcdata{content = list_to_binary(UTC)}]}]}]}, {Acc, R}. diff --git a/src/mod_version.erl b/src/mod_version.erl index 2a436718894..846fd624ca4 100644 --- a/src/mod_version.erl +++ b/src/mod_version.erl @@ -49,11 +49,11 @@ process_iq(Acc, _From, _To, #iq{type = get} = IQ, _Extra) -> {Acc, IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_VERSION}], + attrs = #{<<"xmlns">> => ?NS_VERSION}, children = - [#xmlel{name = <<"name">>, attrs = [], + [#xmlel{name = <<"name">>, children =[#xmlcdata{content = Name}]}, - #xmlel{name = <<"version">>, attrs = [], + #xmlel{name = <<"version">>, children =[#xmlcdata{content = Version}]} ] ++ add_os_info(HostType)}]}}. @@ -61,7 +61,7 @@ process_iq(Acc, _From, _To, #iq{type = get} = IQ, _Extra) -> add_os_info(HostType) -> case gen_mod:get_module_opt(HostType, ?MODULE, os_info) of true -> - [#xmlel{name = <<"os">>, attrs = [], + [#xmlel{name = <<"os">>, children = [#xmlcdata{content = os_info()}]}]; _ -> [] diff --git a/src/mod_websockets.erl b/src/mod_websockets.erl index 7a4d2a43201..aee979727b4 100644 --- a/src/mod_websockets.erl +++ b/src/mod_websockets.erl @@ -105,10 +105,12 @@ init(Req, Opts = #{timeout := Timeout}) -> terminate(_Reason, _Req, #ws_state{fsm_pid = undefined}) -> ok; -terminate(Reason, _Req, #ws_state{fsm_pid = FSM}) - when Reason =:= normal; Reason =:= stop; Reason =:= timeout; Reason =:= remote -> - FSM ! {websockets_closed, undefined}, - ok; +terminate(Reason, _Req, #ws_state{fsm_pid = FSM}) when Reason =:= normal; + Reason =:= stop; + Reason =:= timeout; + Reason =:= remote -> + FSM ! {websockets_closed, undefined}, + ok; terminate({remote, _, _}, _Req, #ws_state{fsm_pid = FSM}) -> FSM ! {websockets_closed, undefined}, ok; @@ -252,13 +254,13 @@ call_fsm_start(SocketData, #{hibernate_after := HibernateAfterTimeout} = Opts) - [{hibernate_after, HibernateAfterTimeout}]). %%-------------------------------------------------------------------- -%% Helpers for handling +%% Helpers for handling %% https://datatracker.ietf.org/doc/rfc7395/ %%-------------------------------------------------------------------- process_client_stream_start([#xmlel{ name = <<"open">>, attrs = Attrs }]) -> - Attrs1 = lists:keyreplace(<<"xmlns">>, 1, Attrs, {<<"xmlns">>, ?NS_CLIENT}), - Attrs2 = [{<<"xmlns:stream">>, ?NS_STREAM} | Attrs1], + Attrs1 = replace_xmlns(Attrs, ?NS_CLIENT), + Attrs2 = Attrs1#{<<"xmlns:stream">> => ?NS_STREAM}, NewStart = #xmlstreamstart{ name = <<"stream:stream">>, attrs = Attrs2 }, [NewStart]; process_client_stream_start(Elements) -> @@ -270,23 +272,26 @@ process_client_stream_end(Element) -> Element. process_server_stream_root(#xmlstreamstart{ name = <<"stream", _/binary>>, attrs = Attrs }) -> - Attrs1 = lists:keydelete(<<"xmlns:stream">>, 1, Attrs), - Attrs2 = lists:keyreplace(<<"xmlns">>, 1, Attrs1, {<<"xmlns">>, ?NS_FRAMING}), + Attrs1 = maps:remove(<<"xmlns:stream">>, Attrs), + Attrs2 = replace_xmlns(Attrs1, ?NS_FRAMING), #xmlel{ name = <<"open">>, attrs = Attrs2 }; process_server_stream_root(#xmlstreamend{ name = <<"stream", _/binary>> }) -> - #xmlel{ name = <<"close">>, attrs = [{<<"xmlns">>, ?NS_FRAMING}] }; + #xmlel{ name = <<"close">>, attrs = #{<<"xmlns">> => ?NS_FRAMING}}; process_server_stream_root(Element) -> Element. -replace_stream_ns(#xmlel{ name = <<"stream:", ElementName/binary>> } = Element) -> - Element#xmlel{ name = ElementName, attrs = [{<<"xmlns">>, ?NS_STREAM} | Element#xmlel.attrs] }; +replace_xmlns(Attrs, XmlNS) when is_map_key(<<"xmlns">>, Attrs) -> + Attrs#{<<"xmlns">> => XmlNS}; +replace_xmlns(Attrs, _XmlNS) -> + Attrs. + +replace_stream_ns(#xmlel{ name = <<"stream:", ElementName/binary>>, attrs = Attrs} = Element) -> + Element#xmlel{ name = ElementName, attrs = Attrs#{<<"xmlns">> => ?NS_STREAM}}; replace_stream_ns(Element) -> case should_have_jabber_client(Element) of true -> - JabberClient = {<<"xmlns">>, <<"jabber:client">>}, - NewAtrrs = lists:keystore(<<"xmlns">>, 1, - Element#xmlel.attrs, JabberClient), - Element#xmlel{attrs = NewAtrrs}; + #xmlel{attrs = Attrs} = Element, + Element#xmlel{attrs = Attrs#{<<"xmlns">> => <<"jabber:client">>}}; false -> Element end. @@ -399,7 +404,7 @@ has_peer_cert(Socket, LOpts) -> get_peer_certificate(Socket, LOpts) /= no_peer_cert. --spec get_peer_certificate(socket(), mongoose_listener:options()) -> +-spec get_peer_certificate(socket(), mongoose_listener:options()) -> mongoose_transport:peercert_return(). get_peer_certificate(#websocket{peercert = undefined}, _) -> no_peer_cert; diff --git a/src/mongoose_client_api/mongoose_client_api_rooms_messages.erl b/src/mongoose_client_api/mongoose_client_api_rooms_messages.erl index 24a7030dc8d..7f04566ceeb 100644 --- a/src/mongoose_client_api/mongoose_client_api_rooms_messages.erl +++ b/src/mongoose_client_api/mongoose_client_api_rooms_messages.erl @@ -88,7 +88,7 @@ handle_post(Req, State = #{jid := UserJid}) -> Args = parse_body(Req), Children = verify_children(get_body(Args) ++ get_marker(Args) ++ get_markable(Args)), UUID = uuid:uuid_to_string(uuid:get_v4(), binary_standard), - Attrs = [{<<"id">>, UUID}], + Attrs = #{<<"id">> => UUID}, case mod_muc_light_api:send_message(RoomJid, UserJid, Children, Attrs) of {ok, _} -> Resp = #{id => UUID}, @@ -127,12 +127,12 @@ get_marker(#{chat_marker := #{type := Type, id := Id}}) when Type == <<"received">>; Type == <<"displayed">>; Type == <<"acknowledged">> -> - [#xmlel{ name = Type, attrs = [{<<"xmlns">>, ?NS_CHAT_MARKERS}, {<<"id">>, Id}] }]; + [#xmlel{ name = Type, attrs = #{<<"xmlns">> => ?NS_CHAT_MARKERS, <<"id">> => Id}}]; get_marker(#{chat_marker := _}) -> throw_error(bad_request, <<"Invalid chat marker">>); get_marker(#{}) -> []. get_markable(#{body := _, markable := true}) -> - [#xmlel{ name = <<"markable">>, attrs = [{<<"xmlns">>, ?NS_CHAT_MARKERS}] }]; + [#xmlel{ name = <<"markable">>, attrs = #{<<"xmlns">> => ?NS_CHAT_MARKERS} }]; get_markable(#{}) -> []. verify_children([]) -> throw_error(bad_request, <<"No valid message elements">>); @@ -192,5 +192,5 @@ add_chat_marker(Item0, Msg) -> add_aff_change_body(Item, #xmlel{attrs = Attrs} = User) -> Item#{type => <<"affiliation">>, - affiliation => proplists:get_value(<<"affiliation">>, Attrs), + affiliation => maps:get(<<"affiliation">>, Attrs, undefined), user => exml_query:cdata(User)}. diff --git a/src/mongoose_data_forms.erl b/src/mongoose_data_forms.erl index 55a4edb8671..d7c7bd309cb 100644 --- a/src/mongoose_data_forms.erl +++ b/src/mongoose_data_forms.erl @@ -103,7 +103,7 @@ form_field_to_kv(_) -> -spec form(form()) -> exml:element(). form(Spec) -> #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, maps:get(type, Spec, <<"form">>)}], + attrs = #{<<"xmlns">> => ?NS_XDATA, <<"type">> => maps:get(type, Spec, <<"form">>)}, children = lists:flatmap(fun(Item) -> form_children(Item, Spec) end, [title, instructions, ns, fields, reported, items]) }. @@ -132,30 +132,30 @@ form_field(M) when is_map(M) -> Validate = form_field_validate(maps:get(validate, M, [])), Values = [form_field_value(Value) || Value <- maps:get(values, M, [])], Options = [form_field_option(Option) || Option <- maps:get(options, M, [])], - Attrs = [{atom_to_binary(K), V} - || {K, V} <- maps:to_list(M), K =/= values, K =/= options, K =/= validate], + Attrs = #{atom_to_binary(K) => V + || K := V <- M, K =/= values, K =/= options, K =/= validate}, #xmlel{name = <<"field">>, attrs = Attrs, children = Values ++ Options ++ Validate}. -spec form_title(binary()) -> exml:element(). form_title(Title) -> - #xmlel{name = <<"title">>, attrs = [], children = [{xmlcdata, Title}]}. + #xmlel{name = <<"title">>, children = [#xmlcdata{content = Title}]}. -spec form_instructions(binary()) -> exml:element(). form_instructions(Instructions) -> - #xmlel{name = <<"instructions">>, attrs = [], children = [{xmlcdata, Instructions}]}. + #xmlel{name = <<"instructions">>, children = [#xmlcdata{content = Instructions}]}. -spec reported_element([exml:element()]) -> exml:element(). reported_element(Fields) -> - #xmlel{name = <<"reported">>, attrs = [], children = Fields}. + #xmlel{name = <<"reported">>, children = Fields}. -spec item_element([exml:element()]) -> exml:element(). item_element(Fields) -> - #xmlel{name = <<"item">>, attrs = [], children = Fields}. + #xmlel{name = <<"item">>, children = Fields}. -spec form_field_option(option()) -> exml:element(). form_field_option({Label, Value}) -> #xmlel{name = <<"option">>, - attrs = [{<<"label">>, Label}], + attrs = #{<<"label">> => Label}, children = [form_field_value(Value)]}; form_field_option(Option) -> form_field_option({Option, Option}). @@ -167,7 +167,7 @@ form_field_value(Value) -> -spec form_field_validate(validate()) -> [exml:element()]. form_field_validate(#{method := Method, datatype := Datatype}) -> [#xmlel{name = <<"validate">>, - attrs = [{<<"xmlns">>, ?NS_DATA_VALIDATE}, {<<"datatype">>, Datatype}], + attrs = #{<<"xmlns">> => ?NS_DATA_VALIDATE, <<"datatype">> => Datatype}, children = form_field_validation_method(Method)}]; form_field_validate(_) -> []. diff --git a/src/mongoose_disco.erl b/src/mongoose_disco.erl index 3884873e8b4..508b19bd694 100644 --- a/src/mongoose_disco.erl +++ b/src/mongoose_disco.erl @@ -203,17 +203,15 @@ extract_result(#{result := Elements}) -> Elements. %% Conversion to XML feature_to_xml(Feature) when is_binary(Feature) -> - #xmlel{name = <<"feature">>, attrs = [{<<"var">>, Feature}]}. + #xmlel{name = <<"feature">>, attrs = #{<<"var">> => Feature}}. item_to_xml(Item) -> #xmlel{name = <<"item">>, - attrs = lists:map(fun({Key, Value}) -> {atom_to_binary(Key, utf8), Value} end, - maps:to_list(Item))}. + attrs = #{atom_to_binary(Key, utf8) => Value || Key := Value <- Item}}. identity_to_xml(Identity) -> #xmlel{name = <<"identity">>, - attrs = lists:map(fun({Key, Value}) -> {atom_to_binary(Key, utf8), Value} end, - maps:to_list(Identity))}. + attrs = #{atom_to_binary(Key, utf8) => Value || Key := Value <- Identity}}. -spec info_to_xml(info()) -> exml:element(). info_to_xml(#{xmlns := NS, fields := Fields}) -> diff --git a/src/mongoose_session_api.erl b/src/mongoose_session_api.erl index ba5b1a6bb41..19b672f761f 100644 --- a/src/mongoose_session_api.erl +++ b/src/mongoose_session_api.erl @@ -191,8 +191,9 @@ set_presence(JID, Type, Show, Status, Priority) -> Children = maybe_pres_status(Status, maybe_pres_priority(Priority, maybe_pres_show(Show, []))), + Attrs = maybe_type_attr(Type), Message = #xmlel{name = <<"presence">>, - attrs = [{<<"from">>, USR}, {<<"to">>, US} | maybe_type_attr(Type)], + attrs = Attrs#{<<"from">> => USR, <<"to">> => US}, children = Children}, ok = mod_presence:set_presence(Pid, Message), {ok, <<"Presence set successfully">>}; @@ -270,11 +271,11 @@ format_user_info(#session{sid = {Microseconds, Pid}, usr = Usr, Uptime = (erlang:system_time(microsecond) - Microseconds) div 1000000, {Usr, Conn, Address, Priority, Node, Uptime}. --spec maybe_type_attr(binary())-> list(). +-spec maybe_type_attr(binary()) -> exml:attrs(). maybe_type_attr(<<"available">>) -> - []; + #{}; maybe_type_attr(Type) -> - [{<<"type">>, Type}]. + #{<<"type">> => Type}. -spec maybe_pres_show(binary(), list()) -> list(). maybe_pres_show(Show, Children) when Show =:= <<>>; diff --git a/src/mongoose_stanza_api.erl b/src/mongoose_stanza_api.erl index a7a7336067f..fd9d85b0378 100644 --- a/src/mongoose_stanza_api.erl +++ b/src/mongoose_stanza_api.erl @@ -188,7 +188,7 @@ do_open_session(#{host_type := HostType, user := JID}) -> -spec build_chat_message(jid:literal_jid(), jid:literal_jid(), binary()) -> exml:element(). build_chat_message(From, To, Body) -> #xmlel{name = <<"message">>, - attrs = add_id([{<<"type">>, <<"chat">>}, {<<"from">>, From}, {<<"to">>, To}]), + attrs = add_id(#{<<"type">> => <<"chat">>, <<"from">> => From, <<"to">> => To}), children = [#xmlel{name = <<"body">>, children = [#xmlcdata{content = Body}]}] }. @@ -198,7 +198,7 @@ build_chat_message(From, To, Body) -> build_headline_message(From, To, Body, Subject) -> Children = maybe_cdata_elem(<<"subject">>, Subject) ++ maybe_cdata_elem(<<"body">>, Body), - Attrs = add_id([{<<"type">>, <<"headline">>}, {<<"from">>, From}, {<<"to">>, To}]), + Attrs = add_id(#{<<"type">> => <<"headline">>, <<"from">> => From, <<"to">> => To}), #xmlel{name = <<"message">>, attrs = Attrs, children = Children}. -spec ensure_id(exml:element()) -> exml:element(). @@ -216,7 +216,7 @@ cdata_elem(Name, Text) when is_binary(Name), is_binary(Text) -> #xmlel{name = Name, children = [#xmlcdata{content = Text}]}. add_id(Attrs) -> - [{<<"id">>, mongoose_bin:gen_from_crypto()} | Attrs]. + Attrs#{<<"id">> => mongoose_bin:gen_from_crypto()}. -spec get_id(exml:element()) -> binary() | undefined. get_id(Stanza) -> diff --git a/src/mongoose_transport.erl b/src/mongoose_transport.erl index 31f35b7092d..0e7261f32ea 100644 --- a/src/mongoose_transport.erl +++ b/src/mongoose_transport.erl @@ -403,7 +403,7 @@ process_data(Data, #state{parser = Parser, {ok, NParser, Elems} -> {[wrap_xml_elements_and_update_metrics(E, ConnectionType) || E <- Elems], NParser}; {error, Reason} -> - {[{xmlstreamerror, Reason}], Parser} + {[#xmlstreamerror{name = Reason}], Parser} end, {NewShaperState, Pause} = mongoose_shaper:update(ShaperState, Size), update_transport_metrics(Data, #{connection_type => ConnectionType, sockmod => SockMod, direction => in}), diff --git a/src/muc/mod_muc.erl b/src/muc/mod_muc.erl index e7fd33e1475..6ee133f1ac3 100644 --- a/src/muc/mod_muc.erl +++ b/src/muc/mod_muc.erl @@ -418,7 +418,7 @@ process_iq_disco_items(MucHost, From, To, #iq{lang = Lang} = IQ) -> Rsm = jlib:rsm_decode(IQ), Res = IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_DISCO_ITEMS}], + attrs = #{<<"xmlns">> => ?NS_DISCO_ITEMS}, children = iq_disco_items(MucHost, From, Lang, Rsm)}]}, ejabberd_router:route(To, From, jlib:iq_to_xml(Res)). @@ -767,7 +767,7 @@ route_by_type(<<"iq">>, {From, To, Acc, Packet}, #muc_state{} = State) -> InfoXML = mongoose_disco:get_info(HostType, ?MODULE, <<>>, Lang), Res = IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, XMLNS}], + attrs = #{<<"xmlns">> => XMLNS}, children = IdentityXML ++ FeatureXML ++ InfoXML}]}, ejabberd_router:route(To, From, jlib:iq_to_xml(Res)); #iq{type = get, xmlns = ?NS_DISCO_ITEMS} = IQ -> @@ -776,7 +776,7 @@ route_by_type(<<"iq">>, {From, To, Acc, Packet}, #muc_state{} = State) -> Result = iq_get_register_info(HostType, MucHost, From, Lang), Res = IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, XMLNS}], + attrs = #{<<"xmlns">> => XMLNS}, children = Result}]}, ejabberd_router:route(To, From, jlib:iq_to_xml(Res)); #iq{type = set, @@ -787,7 +787,7 @@ route_by_type(<<"iq">>, {From, To, Acc, Packet}, #muc_state{} = State) -> {result, IQRes} -> Res = IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, XMLNS}], + attrs = #{<<"xmlns">> => XMLNS}, children = IQRes}]}, ejabberd_router:route(To, From, jlib:iq_to_xml(Res)); {error, Error} -> @@ -797,13 +797,13 @@ route_by_type(<<"iq">>, {From, To, Acc, Packet}, #muc_state{} = State) -> #iq{type = get, xmlns = ?NS_VCARD = XMLNS, lang = Lang} = IQ -> Res = IQ#iq{type = result, sub_el = [#xmlel{name = <<"vCard">>, - attrs = [{<<"xmlns">>, XMLNS}], + attrs = #{<<"xmlns">> => XMLNS}, children = iq_get_vcard(Lang)}]}, ejabberd_router:route(To, From, jlib:iq_to_xml(Res)); #iq{type = get, xmlns = ?NS_MUC_UNIQUE} = IQ -> Res = IQ#iq{type = result, sub_el = [#xmlel{name = <<"unique">>, - attrs = [{<<"xmlns">>, ?NS_MUC_UNIQUE}], + attrs = #{<<"xmlns">> => ?NS_MUC_UNIQUE}, children = [iq_get_unique(From)]}]}, ejabberd_router:route(To, From, jlib:iq_to_xml(Res)); #iq{} -> @@ -947,16 +947,16 @@ room_to_item({{Name, _}, Pid}, MucHost, From, Lang) when is_pid(Pid) -> {item, Desc} -> {true, #xmlel{name = <<"item">>, - attrs = [{<<"jid">>, jid:to_binary({Name, MucHost, <<>>})}, - {<<"name">>, Desc}]}}; + attrs = #{<<"jid">> => jid:to_binary({Name, MucHost, <<>>}), + <<"name">> => Desc}}}; _ -> false end; room_to_item({{Name, _}, _}, MucHost, _, _) -> {true, #xmlel{name = <<"item">>, - attrs = [{<<"jid">>, jid:to_binary({Name, MucHost, <<>>})}, - {<<"name">>, Name}]} + attrs = #{<<"jid">> => jid:to_binary({Name, MucHost, <<>>}), + <<"name">> => Name}} }. record_to_simple(#muc_online_room{name_host = Room, pid = Pid}) -> {Room, Pid}; diff --git a/src/muc/mod_muc_api.erl b/src/muc/mod_muc_api.erl index 4a2a0ba37f9..a1bcd6607b9 100644 --- a/src/muc/mod_muc_api.erl +++ b/src/muc/mod_muc_api.erl @@ -152,15 +152,15 @@ invite_to_room(RoomJID, SenderJID, RecipientJID, Reason) -> ok -> Attrs = case get_room_config(RoomJID) of {ok, #config{password_protected = true, password = Pass}} -> - [{<<"password">>, Pass}]; + #{<<"password">> => Pass}; _ -> - [] + #{} end, %% Direct invitation: i.e. not mediated by MUC room. See XEP 0249. X = #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_CONFERENCE}, - {<<"jid">>, jid:to_binary(RoomJID)}, - {<<"reason">>, Reason} | Attrs] + attrs = Attrs#{<<"xmlns">> => ?NS_CONFERENCE, + <<"jid">> => jid:to_binary(RoomJID), + <<"reason">> => Reason} }, Invite = message(SenderJID, RecipientJID, <<>>, [X]), ejabberd_router:route(SenderJID, RecipientJID, Invite), @@ -182,7 +182,7 @@ send_private_message(RoomJID, SenderJID, ToNick, Message) -> RoomJIDRes = jid:replace_resource(RoomJID, ToNick), Body = #xmlel{name = <<"body">>, children = [#xmlcdata{content = Message}]}, - X = #xmlel{name = <<"x">>, attrs = [{<<"xmlns">>, ?NS_MUC}]}, + X = #xmlel{name = <<"x">>, attrs = #{<<"xmlns">> => ?NS_MUC}}, Stanza = message(SenderJID, RoomJID, <<"chat">>, [Body, X]), ejabberd_router:route(SenderJID, RoomJIDRes, Stanza), {ok, "Message sent successfully"}. @@ -390,8 +390,8 @@ kick_user_from_room_raw(RoomJID, ModJID, Nick, ReasonIn) -> children = [#xmlcdata{content = ReasonIn}] }, Item = #xmlel{name = <<"item">>, - attrs = [{<<"nick">>, Nick}, - {<<"role">>, <<"none">>}], + attrs = #{<<"nick">> => Nick, + <<"role">> => <<"none">>}, children = [ Reason ] }, IQ = iq(<<"set">>, ModJID, RoomJID, [ query(?NS_MUC_ADMIN, [ Item ]) ]), @@ -431,7 +431,7 @@ format_xml_error(#xmlel{name = <<"error">>} = E, Value) -> no_permission_msg(Op, Value) -> io_lib:format("Given user does not have permission to set the ~p ~s", [Value, Op]). -unwrap_xml_error(#xmlel{attrs = [{<<"code">>, Code}, {<<"type">>, Type}], +unwrap_xml_error(#xmlel{attrs = #{<<"code">> := Code, <<"type">> := Type}, children = [#xmlel{name = Condition} | _]}) -> {Code, Type, Condition}. @@ -485,16 +485,17 @@ verify_room(BareRoomJID, OwnerJID) -> end. role_item(Nick, Role) -> - #xmlel{name = <<"item">>, attrs = [{<<"nick">>, Nick}, {<<"role">>, atom_to_binary(Role)}]}. + #xmlel{name = <<"item">>, attrs = #{<<"nick">> => Nick, + <<"role">> => atom_to_binary(Role)}}. affiliation_item(JID, Aff) -> - #xmlel{name = <<"item">>, attrs = [{<<"jid">>, jid:to_binary(JID)}, - {<<"affiliation">>, atom_to_binary(Aff)}]}. + #xmlel{name = <<"item">>, attrs = #{<<"jid">> => jid:to_binary(JID), + <<"affiliation">> => atom_to_binary(Aff)}}. iq(Type, Sender, Recipient, Children) when is_binary(Type), is_list(Children) -> Addresses = address_attributes(Sender, Recipient), #xmlel{name = <<"iq">>, - attrs = Addresses ++ [{<<"type">>, Type}], + attrs = Addresses#{<<"type">> => Type}, children = Children }. @@ -502,7 +503,7 @@ message(Sender, Recipient, Type, Contents) when is_binary(Type), is_list(Content Addresses = address_attributes(Sender, Recipient), Attributes = case Type of <<>> -> Addresses; - _ -> [{<<"type">>, Type} | Addresses] + _ -> Addresses#{<<"type">> => Type} end, #xmlel{name = <<"message">>, attrs = Attributes, @@ -511,7 +512,7 @@ message(Sender, Recipient, Type, Contents) when is_binary(Type), is_list(Content query(XMLNameSpace, Children) when is_binary(XMLNameSpace), is_list(Children) -> #xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, XMLNameSpace}], + attrs = #{<<"xmlns">> => XMLNameSpace}, children = Children}. presence(Sender, Recipient, Password) -> @@ -523,13 +524,14 @@ presence(Sender, Recipient, Password) -> #xmlel{name = <<"presence">>, attrs = address_attributes(Sender, Recipient), children = [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC}], + attrs = #{<<"xmlns">> => ?NS_MUC}, children = Children}]}. exit_room_presence(Sender, Recipient) -> + Addresses = address_attributes(Sender, Recipient), #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, <<"unavailable">>} | address_attributes(Sender, Recipient)], - children = [#xmlel{name = <<"x">>, attrs = [{<<"xmlns">>, ?NS_MUC}]}]}. + attrs = Addresses#{<<"type">> => <<"unavailable">>}, + children = [#xmlel{name = <<"x">>, attrs = #{<<"xmlns">> => ?NS_MUC}}]}. declination(Sender, Recipient) -> iq(<<"set">>, Sender, Recipient, [data_submission()]). @@ -538,8 +540,8 @@ data_submission() -> query(?NS_MUC_OWNER, [mongoose_data_forms:form(#{type => <<"submit">>})]). address_attributes(Sender, Recipient) -> - [{<<"from">>, jid:to_binary(Sender)}, - {<<"to">>, jid:to_binary(Recipient)}]. + #{<<"from">> => jid:to_binary(Sender), + <<"to">> => jid:to_binary(Recipient)}. room_moderator(RoomJID) -> case mod_muc_room:get_room_users(RoomJID) of diff --git a/src/muc/mod_muc_room.erl b/src/muc/mod_muc_room.erl index e33db2a7bd8..d269ea828e1 100644 --- a/src/muc/mod_muc_room.erl +++ b/src/muc/mod_muc_room.erl @@ -447,7 +447,7 @@ locked_state({route, From, _ToNick, Acc, MkQueryResult = fun(Res) -> IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, NS}], + attrs = #{<<"xmlns">> => NS}, children = Res}]} end, {IQRes, StateData3, NextState2} = @@ -596,7 +596,7 @@ normal_state({set_admin_items, UJID, Items}, _From, handle_event({service_message, Msg}, _StateName, StateData) -> MessagePkt = #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"groupchat">>}], + attrs = #{<<"type">> => <<"groupchat">>}, children = [#xmlel{name = <<"body">>, children = [#xmlcdata{content = Msg}]}]}, send_to_all_users(MessagePkt, StateData), @@ -609,7 +609,7 @@ handle_event({service_message, Msg}, _StateName, StateData) -> handle_event({destroy, Reason}, _StateName, StateData) -> {result, [], stop} = destroy_room( - #xmlel{name = <<"destroy">>, attrs = [{<<"xmlns">>, ?NS_MUC_OWNER}], + #xmlel{name = <<"destroy">>, attrs = #{<<"xmlns">> => ?NS_MUC_OWNER}, children = case Reason of none -> []; _Else -> @@ -731,7 +731,7 @@ stop_if_only_owner_is_online(RoomName, 1, #state{users = Users, jid = RoomJID} = case get_affiliation(LastUser, State) of owner -> - ItemAttrs = [{<<"affiliation">>, <<"owner">>}, {<<"role">>, <<"none">>}], + ItemAttrs = #{<<"affiliation">> => <<"owner">>, <<"role">> => <<"none">>}, Packet = unavailable_presence(ItemAttrs, <<"Room hibernation">>), FromRoom = jid:replace_resource(RoomJID, Nick), ejabberd_router:route(FromRoom, LastUser, Packet), @@ -759,7 +759,7 @@ terminate(Reason, _StateName, StateData) -> shutdown -> <<"You are being removed from the room because of a system shutdown">>; _ -> <<"Room terminates">> end, - ItemAttrs = [{<<"affiliation">>, <<"none">>}, {<<"role">>, <<"none">>}], + ItemAttrs = #{<<"affiliation">> => <<"none">>, <<"role">> => <<"none">>}, Packet = unavailable_presence(ItemAttrs, ReasonT), maps_foreach( fun(LJID, Info) -> @@ -788,14 +788,14 @@ unavailable_presence(ItemAttrs, ReasonT) -> ReasonEl = #xmlel{name = <<"reason">>, children = [#xmlcdata{content = ReasonT}]}, #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, <<"unavailable">>}], + attrs = #{<<"type">> => <<"unavailable">>}, children = [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], + attrs = #{<<"xmlns">> => ?NS_MUC_USER}, children = [#xmlel{name = <<"item">>, attrs = ItemAttrs, children = [ReasonEl]}, #xmlel{name = <<"status">>, - attrs = [{<<"code">>, <<"332">>}]} + attrs = #{<<"code">> => <<"332">>}} ]}]}. -spec occupant_jid(user(), 'undefined' | jid:jid()) -> 'error' | jid:jid(). @@ -1244,9 +1244,9 @@ stanzaid_unpack(<<"berd", StanzaIdBase64/binary>>) -> -spec change_stanzaid(binary(), exml:element()) -> exml:element(). -change_stanzaid(NewId, Packet) -> - XE = #xmlel{attrs = Attrs} = jlib:remove_attr(<<"id">>, Packet), - XE#xmlel{attrs = [{<<"id">>, NewId} | Attrs]}. +change_stanzaid(NewId, #xmlel{attrs = Attrs} = Packet) -> + Packet#xmlel{attrs = Attrs#{<<"id">> => NewId}}. + change_stanzaid(PreviousId, ToJID, Packet) -> NewId = stanzaid_pack(PreviousId, ToJID#jid.lresource), change_stanzaid(NewId, Packet). @@ -1358,7 +1358,7 @@ get_error_condition(Packet) -> get_error_condition2(Packet) -> #xmlel{children = EEls} = exml_query:subelement(Packet, <<"error">>), [Condition] = [Name || #xmlel{name = Name, - attrs = [{<<"xmlns">>, ?NS_STANZAS}], + attrs = #{<<"xmlns">> := ?NS_STANZAS}, children = []} <- EEls], {condition, Condition}. @@ -1369,7 +1369,7 @@ expulse_participant(Packet, From, StateData, Reason1) -> Reason2 = <>, NewState = add_user_presence_un( From, - #xmlel{name = <<"presence">>, attrs = [{<<"type">>, <<"unavailable">>}], + #xmlel{name = <<"presence">>, attrs = #{<<"type">> => <<"unavailable">>}, children = [#xmlel{name = <<"status">>, children = [#xmlcdata{content = Reason2}]}]}, StateData), @@ -2269,12 +2269,12 @@ send_new_presence_to_single(NJID, #user{jid = RealJID, nick = Nick, last_presenc case (ReceiverInfo#user.role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [{<<"jid">>, jid:to_binary(RealJID)}, - {<<"affiliation">>, BAffiliation}, - {<<"role">>, BRole}]; + #{<<"jid">> => jid:to_binary(RealJID), + <<"affiliation">> => BAffiliation, + <<"role">> => BRole}; _ -> - [{<<"affiliation">>, BAffiliation}, - {<<"role">>, BRole}] + #{<<"affiliation">> => BAffiliation, + <<"role">> => BRole} end, ItemEls = case Reason of <<>> -> @@ -2313,7 +2313,7 @@ send_new_presence_to_single(NJID, #user{jid = RealJID, nick = Nick, last_presenc end, Packet = jlib:append_subtags( Presence, - [#xmlel{name = <<"x">>, attrs = [{<<"xmlns">>, ?NS_MUC}], + [#xmlel{name = <<"x">>, attrs = #{<<"xmlns">> => ?NS_MUC}, children = [#xmlel{name = <<"item">>, attrs = ItemAttrs, children = ItemEls} | Status2]}]), ejabberd_router:route(jid:replace_resource(StateData#state.jid, Nick), @@ -2345,19 +2345,17 @@ send_existing_presence({_LJID, #user{jid = FromJID, nick = FromNick, ItemAttrs = case (Role == moderator) orelse ((StateData#state.config)#config.anonymous == false) of true -> - [{<<"jid">>, jid:to_binary(FromJID)}, - {<<"affiliation">>, - affiliation_to_binary(FromAffiliation)}, - {<<"role">>, role_to_binary(FromRole)}]; + #{<<"jid">> => jid:to_binary(FromJID), + <<"affiliation">> => affiliation_to_binary(FromAffiliation), + <<"role">> => role_to_binary(FromRole)}; _ -> - [{<<"affiliation">>, - affiliation_to_binary(FromAffiliation)}, - {<<"role">>, role_to_binary(FromRole)}] + #{<<"affiliation">> => affiliation_to_binary(FromAffiliation), + <<"role">> => role_to_binary(FromRole)} end, Packet = jlib:append_subtags( Presence, [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], + attrs = #{<<"xmlns">> => ?NS_MUC_USER}, children = [#xmlel{name = <<"item">>, attrs = ItemAttrs}]}]), ejabberd_router:route(jid:replace_resource(StateData#state.jid, FromNick), RealToJID, Packet). @@ -2454,7 +2452,7 @@ is_nick_change_public(UserInfo, RoomConfig) -> -spec status_code(integer()) -> exml:element(). status_code(Code) -> #xmlel{name = <<"status">>, - attrs = [{<<"code">>, integer_to_binary(Code)}]}. + attrs = #{<<"code">> => integer_to_binary(Code)}}. -spec nick_unavailable_presence(MaybeJID, Nick, Affiliation, Role, MaybeCode) -> exml:element() when @@ -2488,24 +2486,27 @@ nick_available_presence(LastPresence, MaybeJID, Affiliation, Role, MaybeCode) -> Affiliation :: mod_muc:affiliation(), Role :: mod_muc:role(). muc_user_item(MaybeJID, MaybeNick, Affiliation, Role) -> + Attr1 = if MaybeJID =:= undefined -> #{}; + true -> #{<<"jid">> => jid:to_binary(MaybeJID)} + end, + Attr2 = if MaybeNick =:= undefined -> Attr1; + true -> Attr1#{<<"nick">> => MaybeNick} + end, #xmlel{name = <<"item">>, - attrs = [{<<"jid">>, jid:to_binary(MaybeJID)} - || MaybeJID /= undefined] ++ - [{<<"nick">>, MaybeNick} || MaybeNick /= undefined] ++ - [{<<"affiliation">>, affiliation_to_binary(Affiliation)}, - {<<"role">>, role_to_binary(Role)}]}. + attrs = Attr2#{<<"affiliation">> => affiliation_to_binary(Affiliation), + <<"role">> => role_to_binary(Role)}}. -spec muc_user_x([exml:element()]) -> exml:element(). muc_user_x(Children) -> #xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], + attrs = #{<<"xmlns">> => ?NS_MUC_USER}, children = Children}. -spec presence(binary(), [exml:element()]) -> exml:element(). %% Add and validate other types if need be. presence(<<"unavailable">> = Type, Children) -> #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, Type} || Type /= <<"available">>], + attrs = #{<<"type">> => Type || Type /= <<"available">>}, children = Children}. @@ -2588,7 +2589,7 @@ send_history(JID, Shift, StateData) -> -spec send_subject(jid:jid(), ejabberd:lang(), state()) -> mongoose_acc:t(). send_subject(JID, _Lang, StateData = #state{subject = <<>>, subject_author = <<>>}) -> Packet = #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"groupchat">>}], + attrs = #{<<"type">> => <<"groupchat">>}, children = [#xmlel{name = <<"subject">>}, #xmlel{name = <<"body">>}]}, ejabberd_router:route( @@ -2600,13 +2601,13 @@ send_subject(JID, _Lang, StateData) -> TimeStamp = StateData#state.subject_timestamp, RoomJID = StateData#state.jid, Packet = #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"groupchat">>}], + attrs = #{<<"type">> => <<"groupchat">>}, children = [#xmlel{name = <<"subject">>, children = [#xmlcdata{content = Subject}]}, #xmlel{name = <<"delay">>, - attrs = [{<<"xmlns">>, ?NS_DELAY}, - {<<"from">>, jid:to_binary(RoomJID)}, - {<<"stamp">>, TimeStamp}]}]}, + attrs = #{<<"xmlns">> => ?NS_DELAY, + <<"from">> => jid:to_binary(RoomJID), + <<"stamp">> => TimeStamp}}]}, ejabberd_router:route(RoomJID, JID, Packet). @@ -2708,14 +2709,14 @@ items_with_affiliation(BAffiliation, StateData) -> lists:map( fun({JID, {Affiliation, Reason}}) -> #xmlel{name = <<"item">>, - attrs = [{<<"affiliation">>, affiliation_to_binary(Affiliation)}, - {<<"jid">>, jid:to_binary(JID)}], + attrs = #{<<"affiliation">> => affiliation_to_binary(Affiliation), + <<"jid">> => jid:to_binary(JID)}, children = [#xmlel{name = <<"reason">>, children = [#xmlcdata{content = Reason}]}]}; ({JID, Affiliation}) -> #xmlel{name = <<"item">>, - attrs = [{<<"affiliation">>, affiliation_to_binary(Affiliation)}, - {<<"jid">>, jid:to_binary(JID)}]} + attrs = #{<<"affiliation">> => affiliation_to_binary(Affiliation), + <<"jid">> => jid:to_binary(JID)}} end, search_affiliation(BAffiliation, StateData)). @@ -2726,10 +2727,10 @@ user_to_item(#user{role = Role, }, StateData) -> Affiliation = get_affiliation(JID, StateData), #xmlel{name = <<"item">>, - attrs = [{<<"role">>, role_to_binary(Role)}, - {<<"affiliation">>, affiliation_to_binary(Affiliation)}, - {<<"nick">>, Nick}, - {<<"jid">>, jid:to_binary(JID)}]}. + attrs = #{<<"role">> => role_to_binary(Role), + <<"affiliation">> => affiliation_to_binary(Affiliation), + <<"nick">> => Nick, + <<"jid">> => jid:to_binary(JID)}}. -spec search_role(mod_muc:role(), state()) -> users_pairs(). @@ -3089,14 +3090,14 @@ send_kickban_presence1(UJID, Reason, Code, Affiliation, StateData) -> BAffiliation = affiliation_to_binary(Affiliation), BannedJIDString = jid:to_binary(RealJID), F = fun(Info) -> - JidAttrList = case (Info#user.role == moderator) orelse - ((StateData#state.config)#config.anonymous - == false) of - true -> [{<<"jid">>, BannedJIDString}]; - false -> [] + JidAttrList = + case (Info#user.role == moderator) orelse + ((StateData#state.config)#config.anonymous == false) of + true -> #{<<"jid">> => BannedJIDString}; + false -> #{} end, - ItemAttrs = [{<<"affiliation">>, BAffiliation}, - {<<"role">>, <<"none">>}] ++ JidAttrList, + ItemAttrs = JidAttrList#{<<"affiliation">> => BAffiliation, + <<"role">> => <<"none">>}, ItemEls = case Reason of <<>> -> []; @@ -3104,14 +3105,14 @@ send_kickban_presence1(UJID, Reason, Code, Affiliation, StateData) -> [#xmlel{name = <<"reason">>, children = [#xmlcdata{content = Reason}]}] end, Packet = #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, <<"unavailable">>}], + attrs = #{<<"type">> => <<"unavailable">>}, children = [#xmlel{name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], + attrs = #{<<"xmlns">> => ?NS_MUC_USER}, children = [#xmlel{name = <<"item">>, attrs = ItemAttrs, children = ItemEls}, #xmlel{name = <<"status">>, - attrs = [{<<"code">>, Code}]}]}]}, + attrs = #{<<"code">> => Code}}]}]}, ejabberd_router:route( jid:replace_resource(StateData#state.jid, Nick), Info#user.jid, @@ -3721,14 +3722,14 @@ send_to_all_users(Packet, StateData=#state{jid=RoomJID}) -> presence_stanza_of_type_unavailable(DestroyEl) -> ItemEl = #xmlel{ name = <<"item">>, - attrs = [{<<"affiliation">>, <<"none">>}, {<<"role">>, <<"none">>}]}, + attrs = #{<<"affiliation">> => <<"none">>, <<"role">> => <<"none">>}}, XEl = #xmlel{ name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], + attrs = #{<<"xmlns">> => ?NS_MUC_USER}, children = [ItemEl, DestroyEl]}, #xmlel{ name = <<"presence">>, - attrs = [{<<"type">>, <<"unavailable">>}], + attrs = #{<<"type">> => <<"unavailable">>}, children = [XEl]}. @@ -3862,8 +3863,8 @@ get_mucroom_disco_items(StateData=#state{jid=RoomJID}) -> disco_item(User=#user{nick=Nick}, RoomJID) -> #xmlel{ name = <<"item">>, - attrs = [{<<"jid">>, jid:to_binary(occupant_jid(User, RoomJID))}, - {<<"name">>, Nick}]}. + attrs = #{<<"jid">> => jid:to_binary(occupant_jid(User, RoomJID)), + <<"name">> => Nick}}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Handle voice request or approval (XEP-0045 7.13, 8.6) @@ -3954,7 +3955,7 @@ create_invite(FromJID, InviteEl, Lang, StateData) -> children = [#xmlcdata{content = Reason}]}, OutInviteEl = #xmlel{ name = <<"invite">>, - attrs = [{<<"from">>, jid:to_binary(FromJID)}], + attrs = #{<<"from">> => jid:to_binary(FromJID)}, children = [ReasonEl] ++ ContinueEl}, PasswdEl = create_password_elem(StateData), BodyEl = invite_body_elem(FromJID, Reason, Lang, StateData), @@ -4048,11 +4049,11 @@ create_invite_message_elem(InviteEl, BodyEl, PasswdEl, Reason) when is_list(PasswdEl), is_binary(Reason) -> UserXEl = #xmlel{ name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_USER}], + attrs = #{<<"xmlns">> => ?NS_MUC_USER}, children = [InviteEl|PasswdEl]}, #xmlel{ name = <<"message">>, - attrs = [{<<"type">>, <<"normal">>}], + attrs = #{<<"type">> => <<"normal">>}, children = [UserXEl, BodyEl]}. @@ -4094,8 +4095,8 @@ check_decline_invitation(Packet) -> send_decline_invitation({Packet, XEl, DEl, ToJID}, RoomJID, FromJID) -> FromString = jid:to_binary(FromJID), #xmlel{name = <<"decline">>, attrs = DAttrs, children = DEls} = DEl, - DAttrs2 = lists:keydelete(<<"to">>, 1, DAttrs), - DAttrs3 = [{<<"from">>, FromString} | DAttrs2], + DAttrs2 = maps:remove(<<"to">>, DAttrs), + DAttrs3 = DAttrs2#{<<"from">> => FromString}, DEl2 = #xmlel{name = <<"decline">>, attrs = DAttrs3, children = DEls}, XEl2 = jlib:replace_subelement(XEl, DEl2), Packet2 = jlib:replace_subelement(Packet, XEl2), @@ -4308,8 +4309,8 @@ route_voice_approval({form, RoleName}, From, _Packet, _Lang, StateData) -> StateData; route_voice_approval({role, BRole, Nick}, From, Packet, Lang, StateData) -> Items = [#xmlel{name = <<"item">>, - attrs = [{<<"role">>, BRole}, - {<<"nick">>, Nick}]}], + attrs = #{<<"role">> => BRole, + <<"nick">> => Nick}}], case process_admin_items_set(From, Items, Lang, StateData) of {result, _Res, SD1} -> SD1; {error, Error} -> @@ -4407,7 +4408,7 @@ do_route_iq(Acc, Res1, #routed_iq{iq = #iq{xmlns = XMLNS, sub_el = SubEl} = IQ, { IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, XMLNS}], + attrs = #{<<"xmlns">> => XMLNS}, children = Res}]}, case SD of stop -> {stop, StateData}; @@ -4571,26 +4572,25 @@ get_current_timestamp() -> read_hibernate_timeout(HostType) -> gen_mod:get_module_opt(HostType, mod_muc, hibernate_timeout). -maybe_add_x_element(Msg) -> - {xmlel, Type, InfoXML, Children} = Msg, - case lists:member({xmlel, <<"x">>, [{<<"xmlns">>, ?NS_MUC_USER}], []}, Children) of +maybe_add_x_element(#xmlel{children = Children} = Msg) -> + XEl = #xmlel{name = <<"x">>, attrs = #{<<"xmlns">> => ?NS_MUC_USER}, children = []}, + case lists:member(XEl, Children) of true -> Msg; false -> - NewChildren = lists:append(Children, - [{xmlel, <<"x">>, [{<<"xmlns">>, ?NS_MUC_USER}], []}]), - {xmlel, Type, InfoXML, NewChildren} + NewChildren = lists:append(Children, [XEl]), + Msg#xmlel{children = NewChildren} end. kick_stanza_for_old_protocol(Packet) -> Lang = exml_query:attr(Packet, <<"xml:lang">>, <<>>), ErrText = <<"You are not in the room.">>, ErrText2 = translate:translate(Lang, ErrText), - Response = #xmlel{name = <<"presence">>, attrs = [{<<"type">>, <<"unavailable">>}]}, - ItemAttrs = [{<<"affiliation">>, <<"none">>}, {<<"role">>, <<"none">>}], + Response = #xmlel{name = <<"presence">>, attrs = #{<<"type">> => <<"unavailable">>}}, + ItemAttrs = #{<<"affiliation">> => <<"none">>, <<"role">> => <<"none">>}, ItemEls = [#xmlel{name = <<"reason">>, children = [#xmlcdata{content = ErrText2}]}], Status = [status_code(110), status_code(307), status_code(333)], jlib:append_subtags( Response, - [#xmlel{name = <<"x">>, attrs = [{<<"xmlns">>, ?NS_MUC}], + [#xmlel{name = <<"x">>, attrs = #{<<"xmlns">> => ?NS_MUC}, children = [#xmlel{name = <<"item">>, attrs = ItemAttrs, children = ItemEls} | Status]}]). diff --git a/src/muc_light/mod_muc_light_api.erl b/src/muc_light/mod_muc_light_api.erl index 7264799dae2..91c329ca457 100644 --- a/src/muc_light/mod_muc_light_api.erl +++ b/src/muc_light/mod_muc_light_api.erl @@ -81,9 +81,9 @@ change_affiliation(RoomJID, SenderJID, RecipientJID, Op) -> {ok | user_not_found | muc_server_not_found | room_not_found | not_room_member, iolist()}. send_message(RoomJID, SenderJID, Text) when is_binary(Text) -> Body = #xmlel{name = <<"body">>, children = [#xmlcdata{content = Text}]}, - send_message(RoomJID, SenderJID, [Body], []). + send_message(RoomJID, SenderJID, [Body], #{}). --spec send_message(jid:jid(), jid:jid(), [exml:element()], [exml:attr()]) -> +-spec send_message(jid:jid(), jid:jid(), [exml:element()], exml:attrs()) -> {ok | user_not_found | muc_server_not_found | room_not_found | not_room_member, iolist()}. send_message(RoomJID, SenderJID, Children, ExtraAttrs) -> M = #{user => SenderJID, room => RoomJID, children => Children, attrs => ExtraAttrs}, @@ -264,7 +264,7 @@ do_send_message(#{user := SenderJID, room := RoomJID, children := Children, attr SenderBare = jid:to_bare(SenderJID), RoomBare = jid:to_bare(RoomJID), Stanza = #xmlel{name = <<"message">>, - attrs = [{<<"type">>, <<"groupchat">>} | ExtraAttrs], + attrs = ExtraAttrs#{<<"type">> => <<"groupchat">>}, children = Children}, ejabberd_router:route(SenderBare, RoomBare, Stanza), {ok, "Message sent successfully"}. @@ -357,7 +357,7 @@ do_set_blocking_list(#{user := UserJID, user_host_type := HostType, items := Ite -spec blocking_item(blocking_item()) -> exml:element(). blocking_item({What, Action, Who}) -> #xmlel{name = atom_to_binary(What), - attrs = [{<<"action">>, atom_to_binary(Action)}], + attrs = #{<<"action">> => atom_to_binary(Action)}, children = [#xmlcdata{ content = jid:to_binary(Who)}] }. @@ -399,22 +399,22 @@ ensure_keys_are_binaries(Conf) -> iq(To, From, Type, Children) -> UUID = uuid:uuid_to_string(uuid:get_v4(), binary_standard), #xmlel{name = <<"iq">>, - attrs = [{<<"from">>, From}, - {<<"to">>, To}, - {<<"type">>, Type}, - {<<"id">>, UUID}], + attrs = #{<<"from">> => From, + <<"to">> => To, + <<"type">> => Type, + <<"id">> => UUID}, children = Children }. query(NS, Children) when is_binary(NS), is_list(Children) -> #xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, NS}], + attrs = #{<<"xmlns">> => NS}, children = Children }. affiliate(JID, Kind) when is_binary(JID), is_binary(Kind) -> #xmlel{name = <<"user">>, - attrs = [{<<"affiliation">>, Kind}], + attrs = #{<<"affiliation">> => Kind}, children = [ #xmlcdata{ content = JID } ] }. diff --git a/src/muc_light/mod_muc_light_codec_legacy.erl b/src/muc_light/mod_muc_light_codec_legacy.erl index b0b8bf0c5d2..b3f3f5473ce 100644 --- a/src/muc_light/mod_muc_light_codec_legacy.erl +++ b/src/muc_light/mod_muc_light_codec_legacy.erl @@ -52,11 +52,9 @@ encode({#msg{} = Msg, AffUsers}, Sender, RoomBareJid, HandleFun, Acc) -> Aff = get_sender_aff(AffUsers, US), FromNick = jid:to_bare_binary(Sender), {RoomJID, RoomBin} = jids_from_room_with_resource(RoomBareJid, FromNick), - Attrs = [ - {<<"id">>, Msg#msg.id}, - {<<"type">>, <<"groupchat">>}, - {<<"from">>, RoomBin} - ], + Attrs = #{<<"id">> => Msg#msg.id, + <<"type">> => <<"groupchat">>, + <<"from">> => RoomBin}, MsgForArch = #xmlel{ name = <<"message">>, attrs = Attrs, children = Msg#msg.children }, TS = mongoose_acc:timestamp(Acc), EventData = #{from_nick => FromNick, @@ -94,7 +92,7 @@ encode(OtherCase, Sender, RoomBareJid, HandleFun, Acc) -> mongoose_acc:t(). encode_error(_, OrigFrom, OrigTo, #xmlel{ name = <<"presence">> } = OrigPacket, Acc) -> %% The only error case for valid presence is registration-required for room creation - X = #xmlel{ name = <<"x">>, attrs = [{<<"xmlns">>, ?NS_MUC}] }, + X = #xmlel{ name = <<"x">>, attrs = #{<<"xmlns">> => ?NS_MUC} }, mod_muc_light_codec_backend:encode_error({error, registration_required}, [X], OrigFrom, OrigTo, OrigPacket, Acc); encode_error(ErrMsg, OrigFrom, OrigTo, OrigPacket, Acc) -> @@ -107,25 +105,23 @@ encode_error(ErrMsg, OrigFrom, OrigTo, OrigPacket, Acc) -> -spec decode_message(Packet :: exml:element()) -> {ok, muc_light_packet()} | {error, bad_request} | ignore. decode_message(#xmlel{ attrs = Attrs, children = Children }) -> - decode_message_by_type(lists:keyfind(<<"type">>, 1, Attrs), - lists:keyfind(<<"id">>, 1, Attrs), Children). + decode_message_by_type(Attrs, Children). --spec decode_message_by_type(Type :: {binary(), binary()} | false, - Id :: {binary(), binary()} | false, +-spec decode_message_by_type(exml:attrs(), Children :: [jlib:xmlch()]) -> {ok, msg() | {set, mod_muc_light_room_config:kv()}} | {error, bad_request} | ignore. -decode_message_by_type({_, <<"groupchat">>}, _, [#xmlel{ name = <<"subject">> } = SubjectEl]) -> +decode_message_by_type(#{<<"type">> := <<"groupchat">>}, [#xmlel{ name = <<"subject">> } = SubjectEl]) -> {ok, {set, #config{ raw_config = [{<<"subject">>, exml_query:cdata(SubjectEl)}] }}}; -decode_message_by_type({_, <<"groupchat">>}, Id, Children) -> - {ok, #msg{ children = Children, id = ensure_id(Id) }}; -decode_message_by_type({_, <<"error">>}, _, _) -> +decode_message_by_type(#{<<"type">> := <<"groupchat">>} = Attrs, Children) -> + {ok, #msg{ children = Children, id = ensure_id(Attrs)}}; +decode_message_by_type(#{<<"type">> := <<"error">>}, _) -> ignore; -decode_message_by_type(_, _, _) -> +decode_message_by_type(_, _) -> {error, bad_request}. --spec ensure_id(Id :: {binary(), binary()} | false) -> binary(). -ensure_id(false) -> mongoose_bin:gen_from_timestamp(); -ensure_id({_, Id}) -> Id. +-spec ensure_id(exml:attrs()) -> binary(). +ensure_id(#{<<"id">> := Id}) -> Id; +ensure_id(_) -> mongoose_bin:gen_from_timestamp(). %%==================================================================== %% IQ decoding @@ -165,7 +161,7 @@ decode_iq(_From, #iq{ xmlns = ?NS_PRIVACY, type = get, id = ID }) -> {ok, {get, #blocking{ id = ID }}}; decode_iq(From, IQ = #iq{ xmlns = ?NS_PRIVACY, type = set, sub_el = #xmlel{ children = Lists }, id = ID }) -> - case lists:keyfind([{<<"name">>, ?NS_MUC_LIGHT}], #xmlel.attrs, Lists) of + case lists:keyfind(#{<<"name">> => ?NS_MUC_LIGHT}, #xmlel.attrs, Lists) of false -> ignore; List -> @@ -256,8 +252,8 @@ encode_meta({get, #disco_info{ id = ID }}, RoomJID, SenderJID, _HandleFun, Acc) encode_meta({get, #disco_items{ rooms = Rooms, id = ID, rsm = RSMOut }}, _RoomJID, _SenderJID, _HandleFun, _Acc) -> DiscoEls = [ #xmlel{ name = <<"item">>, - attrs = [{<<"jid">>, <>}, - {<<"name">>, RoomName}] } + attrs = #{<<"jid">> => <>, + <<"name">> => RoomName}} || {{RoomU, RoomS}, RoomName, _RoomVersion} <- Rooms ], {iq_reply, ?NS_DISCO_ITEMS, jlib:rsm_encode(RSMOut) ++ DiscoEls, ID}; encode_meta({get, #config{} = Config}, _RoomJID, _SenderJID, _HandleFun, _Acc) -> @@ -281,7 +277,7 @@ encode_meta({get, #blocking{} = Blocking}, RoomJID, _SenderJID, _HandleFun, Acc) MUCHost = mongoose_subdomain_utils:get_fqdn(mod_muc_light:subdomain_pattern(HostType), ServerHost), BlockingEls = [ blocking_to_el(BlockingItem, MUCHost) || BlockingItem <- Blocking#blocking.items ], - Blocklist = #xmlel{ name = <<"list">>, attrs = [{<<"name">>, ?NS_MUC_LIGHT}], + Blocklist = #xmlel{ name = <<"list">>, attrs = #{<<"name">> => ?NS_MUC_LIGHT}, children = BlockingEls }, {iq_reply, ?NS_PRIVACY, [Blocklist], Blocking#blocking.id}; encode_meta({set, #blocking{ id = ID }}, _RoomJID, _SenderJID, _HandleFun, _Acc) -> @@ -290,13 +286,13 @@ encode_meta({set, #create{} = Create, _UniqueRequested}, RoomJID, _SenderJID, Ha [{{ToU, ToS}, CreatorAff}] = Create#create.aff_users, ToBin = jid:to_binary({ToU, ToS, <<>>}), {From, FromBin} = jids_from_room_with_resource(RoomJID, ToBin), - Attrs = [{<<"from">>, FromBin}], + Attrs = #{<<"from">> => FromBin}, {AffBin, RoleBin} = case CreatorAff of owner -> {<<"owner">>, <<"moderator">>}; member -> {<<"member">>, <<"participant">>} end, NotifEls = [ #xmlel{ name = <<"item">>, - attrs = [{<<"affiliation">>, AffBin}, {<<"role">>, RoleBin}]}, + attrs = #{<<"affiliation">> => AffBin, <<"role">> => RoleBin}}, status(<<"110">>), status(<<"201">>) ], Children = envelope(?NS_MUC_USER, NotifEls), @@ -306,11 +302,11 @@ encode_meta({set, #destroy{ id = ID }, AffUsers}, RoomJID, _SenderJID, HandleFun lists:foreach( fun({{U, S}, _}) -> FromJID = jid:replace_resource(RoomJID, jid:to_binary({U, S, <<>>})), - Attrs = [{<<"from">>, jid:to_binary(FromJID)}, - {<<"type">>, <<"unavailable">>}], + Attrs = #{<<"from">> => jid:to_binary(FromJID), + <<"type">> => <<"unavailable">>}, Children = [ #xmlel{ name = <<"item">>, - attrs = [{<<"affiliation">>, <<"none">>}, - {<<"role">>, <<"none">>}] }, + attrs = #{<<"affiliation">> => <<"none">>, + <<"role">> => <<"none">>}}, #xmlel{ name = <<"destroy">> } ], send_to_aff_user(FromJID, U, S, <<"presence">>, Attrs, envelope(?NS_MUC_USER, Children), HandleFun) @@ -319,11 +315,9 @@ encode_meta({set, #destroy{ id = ID }, AffUsers}, RoomJID, _SenderJID, HandleFun {iq_reply, ID}; encode_meta({set, #config{ raw_config = [{<<"subject">>, Subject}], id = ID }, AffUsers}, RoomJID, _SenderJID, HandleFun, _Acc) -> - Attrs = [ - {<<"id">>, ID}, - {<<"type">>, <<"groupchat">>}, - {<<"from">>, jid:to_binary(RoomJID)} - ], + Attrs = #{<<"id">> => ID, + <<"type">> => <<"groupchat">>, + <<"from">> => jid:to_binary(RoomJID)}, SubjectEl = #xmlel{ name = <<"subject">>, children = [ #xmlcdata{ content = Subject } ] }, lists:foreach( fun({{U, S}, _}) -> @@ -331,9 +325,9 @@ encode_meta({set, #config{ raw_config = [{<<"subject">>, Subject}], id = ID }, A end, AffUsers), noreply; encode_meta({set, #config{} = Config, AffUsers}, RoomJID, _SenderJID, HandleFun, _Acc) -> - Attrs = [{<<"id">>, Config#config.id}, - {<<"from">>, jid:to_binary(RoomJID)}, - {<<"type">>, <<"groupchat">>}], + Attrs = #{<<"id">> => Config#config.id, + <<"from">> => jid:to_binary(RoomJID), + <<"type">> => <<"groupchat">>}, ConfigNotif = envelope(?NS_MUC_USER, [status(<<"104">>)]), lists:foreach( fun({{U, S}, _}) -> @@ -351,15 +345,14 @@ identity() -> -spec aff_user_to_item(aff_user()) -> exml:element(). aff_user_to_item({User, Aff}) -> UserBin = jid:to_binary(User), - {RoleBin, NickEl} = case Aff of - owner -> {<<"moderator">>, [{<<"nick">>, UserBin}]}; - member -> {<<"participant">>, [{<<"nick">>, UserBin}]}; - none -> {<<"none">>, []} + Attrs = case Aff of + owner -> #{<<"role">> => <<"moderator">>, <<"nick">> => UserBin}; + member -> #{<<"role">> => <<"participant">>, <<"nick">> => UserBin}; + none -> #{<<"role">> => <<"none">>} end, #xmlel{ name = <<"item">>, - attrs = [{<<"affiliation">>, mod_muc_light_utils:aff2b(Aff)}, - {<<"jid">>, UserBin}, - {<<"role">>, RoleBin} | NickEl] }. + attrs = Attrs#{<<"affiliation">> => mod_muc_light_utils:aff2b(Aff), + <<"jid">> => UserBin}}. -spec blocking_to_el(BlockingItem :: blocking_item(), Service :: binary()) -> exml:element(). blocking_to_el({What, Action, {WhoU, WhoS}}, Service) -> @@ -369,16 +362,14 @@ blocking_to_el({What, Action, {WhoU, WhoS}}, Service) -> user -> <> end, #xmlel{ name = <<"item">>, - attrs = [ - {<<"type">>, <<"jid">>}, - {<<"value">>, Value}, - {<<"action">>, action2b(Action)}, - {<<"order">>, <<"1">>} - ] }. + attrs = #{<<"type">> => <<"jid">>, + <<"value">> => Value, + <<"action">> => action2b(Action), + <<"order">> => <<"1">>}}. -spec envelope(XMLNS :: binary(), Children :: [jlib:xmlch()]) -> [jlib:xmlch()]. envelope(XMLNS, Children) -> - [ #xmlel{ name = <<"x">>, attrs = [{<<"xmlns">>, XMLNS}], children = Children } ]. + [ #xmlel{ name = <<"x">>, attrs = #{<<"xmlns">> => XMLNS}, children = Children } ]. -spec bcast_aff_messages(Room :: jid:jid(), OldAffUsers :: aff_users(), NewAffUsers :: aff_users(), SenderJID :: jid:jid(), @@ -396,10 +387,10 @@ bcast_aff_messages(Room, [{{ToU, ToS} = User, _} | ROldAffUsers], [{User, _} | R ChangedUserBin = jid:to_binary({ChangedU, ChangedS, <<>>}), {From, FromBin} = jids_from_room_with_resource(Room, ChangedUserBin), - Attrs0 = [{<<"from">>, FromBin}], + Attrs0 = #{<<"from">> => FromBin}, ElToEnvelope0 = aff_user_to_item(ChangedAffUser), {Attrs, ElsToEnvelope} = case NewAff of - none -> {[{<<"type">>, <<"unavailable">>} | Attrs0], + none -> {Attrs0#{<<"type">> => <<"unavailable">>}, [ElToEnvelope0, status(<<"321">>)]}; _ -> {Attrs0, [ElToEnvelope0]} end, @@ -416,9 +407,9 @@ bcast_aff_messages(Room, OldAffUsers, [{{ToU, ToS}, _} | RNewAffUsers], InviterBin = jid:to_binary({SenderJID#jid.luser, SenderJID#jid.lserver, <<>>}), RoomBin = jid:to_binary(jid:to_lower(Room)), InviteEl = #xmlel{ name = <<"invite">>, - attrs = [{<<"from">>, InviterBin}] }, + attrs = #{<<"from">> => InviterBin} }, NotifForNewcomer = envelope(?NS_MUC_USER, [InviteEl]), - send_to_aff_user(Room, ToU, ToS, <<"message">>, [{<<"from">>, RoomBin}], + send_to_aff_user(Room, ToU, ToS, <<"message">>, #{<<"from">> => RoomBin}, NotifForNewcomer, HandleFun), bcast_aff_messages(Room, OldAffUsers, RNewAffUsers, SenderJID, ChangedAffUsers, HandleFun). @@ -427,19 +418,19 @@ bcast_aff_messages(Room, OldAffUsers, [{{ToU, ToS}, _} | RNewAffUsers], msg_to_leaving_user(Room, {ToU, ToS} = User, HandleFun) -> UserBin = jid:to_binary({ToU, ToS, <<>>}), {From, FromBin} = jids_from_room_with_resource(Room, UserBin), - Attrs = [{<<"from">>, FromBin}, - {<<"type">>, <<"unavailable">>}], + Attrs = #{<<"from">> => FromBin, + <<"type">> => <<"unavailable">>}, NotifForLeaving = envelope(?NS_MUC_USER, [ aff_user_to_item({User, none}), status(<<"321">>) ]), send_to_aff_user(From, ToU, ToS, <<"presence">>, Attrs, NotifForLeaving, HandleFun). -spec send_to_aff_user(From :: jid:jid(), ToU :: jid:luser(), ToS :: jid:lserver(), - Name :: binary(), Attrs :: [{binary(), binary()}], + Name :: binary(), Attrs :: exml:attrs(), Children :: [jlib:xmlch()], HandleFun :: mod_muc_light_codec_backend:encoded_packet_handler()) -> ok. send_to_aff_user(From, ToU, ToS, Name, Attrs, Children, HandleFun) -> To = jid:make_noprep(ToU, ToS, <<>>), ToBin = jid:to_binary({ToU, ToS, <<>>}), - Packet = #xmlel{ name = Name, attrs = [{<<"to">>, ToBin} | Attrs], + Packet = #xmlel{ name = Name, attrs = Attrs#{<<"to">> => ToBin}, children = Children }, HandleFun(From, To, Packet). @@ -453,12 +444,10 @@ jids_from_room_with_resource(RoomJID, Resource) -> -spec make_iq_result(FromBin :: binary(), ToBin :: binary(), ID :: binary(), XMLNS :: binary(), Els :: [jlib:xmlch()] | undefined) -> exml:element(). make_iq_result(FromBin, ToBin, ID, XMLNS, Els) -> - Attrs = [ - {<<"from">>, FromBin}, - {<<"to">>, ToBin}, - {<<"id">>, ID}, - {<<"type">>, <<"result">>} - ], + Attrs = #{<<"from">> => FromBin, + <<"to">> => ToBin, + <<"id">> => ID, + <<"type">> => <<"result">>}, Query = make_query_el(XMLNS, Els), #xmlel{ name = <<"iq">>, attrs = Attrs, children = Query }. @@ -466,10 +455,10 @@ make_iq_result(FromBin, ToBin, ID, XMLNS, Els) -> make_query_el(_, undefined) -> []; make_query_el(XMLNS, Els) -> - [#xmlel{ name = <<"query">>, attrs = [{<<"xmlns">>, XMLNS}], children = Els }]. + [#xmlel{ name = <<"query">>, attrs = #{<<"xmlns">> => XMLNS}, children = Els }]. -spec status(Code :: binary()) -> exml:element(). -status(Code) -> #xmlel{ name = <<"status">>, attrs = [{<<"code">>, Code}] }. +status(Code) -> #xmlel{ name = <<"status">>, attrs = #{<<"code">> => Code} }. %%==================================================================== %% Common helpers and internal functions diff --git a/src/muc_light/mod_muc_light_codec_modern.erl b/src/muc_light/mod_muc_light_codec_modern.erl index 59dbbbfb87e..45b0813d380 100644 --- a/src/muc_light/mod_muc_light_codec_modern.erl +++ b/src/muc_light/mod_muc_light_codec_modern.erl @@ -56,11 +56,9 @@ encode({#msg{} = Msg, AffUsers}, Sender, RoomBareJid, HandleFun, Acc) -> FromNick = jid:to_binary(US), Aff = get_sender_aff(AffUsers, US), {RoomJID, RoomBin} = jids_from_room_with_resource(RoomBareJid, FromNick), - Attrs = [ - {<<"id">>, Msg#msg.id}, - {<<"type">>, <<"groupchat">>}, - {<<"from">>, RoomBin} - ], + Attrs = #{ <<"id">> => Msg#msg.id, + <<"type">> => <<"groupchat">>, + <<"from">> => RoomBin }, MsgForArch = #xmlel{ name = <<"message">>, attrs = Attrs, children = Msg#msg.children }, TS = mongoose_acc:timestamp(Acc), EventData = #{from_nick => FromNick, @@ -113,23 +111,20 @@ encode_error(ErrMsg, OrigFrom, OrigTo, OrigPacket, Acc) -> -spec decode_message(Packet :: exml:element()) -> {ok, muc_light_packet()} | {error, bad_request} | ignore. decode_message(#xmlel{ attrs = Attrs, children = Children }) -> - decode_message_by_type(lists:keyfind(<<"type">>, 1, Attrs), - lists:keyfind(<<"id">>, 1, Attrs), Children). + decode_message_by_type(Attrs, Children). --spec decode_message_by_type(Type :: {binary(), binary()} | false, - Id :: {binary(), binary()} | false, - Children :: [jlib:xmlch()]) -> +-spec decode_message_by_type(exml:attrs(), Children :: [jlib:xmlch()]) -> {ok, msg()} | {error, bad_request} | ignore. -decode_message_by_type({_, <<"groupchat">>}, Id, Children) -> - {ok, #msg{ children = Children, id = ensure_id(Id) }}; -decode_message_by_type({_, <<"error">>}, _, _) -> +decode_message_by_type(#{<<"type">> := <<"groupchat">>} = Attrs, Children) -> + {ok, #msg{ children = Children, id = ensure_id(Attrs) }}; +decode_message_by_type(#{<<"type">> := <<"error">>}, _) -> ignore; -decode_message_by_type(_, _, _) -> +decode_message_by_type(_, _) -> {error, bad_request}. --spec ensure_id(Id :: {binary(), binary()} | false) -> binary(). -ensure_id(false) -> mongoose_bin:gen_from_timestamp(); -ensure_id({_, Id}) -> Id. +-spec ensure_id(exml:attrs()) -> binary(). +ensure_id(#{<<"id">> := Id}) -> Id; +ensure_id(_) -> mongoose_bin:gen_from_timestamp(). %%==================================================================== %% IQ decoding @@ -229,7 +224,7 @@ parse_aff_users([], AffUsersAcc) -> {ok, AffUsersAcc}; parse_aff_users([#xmlcdata{} | RItemsEls], AffUsersAcc) -> parse_aff_users(RItemsEls, AffUsersAcc); -parse_aff_users([#xmlel{ name = <<"user">>, attrs = [{<<"affiliation">>, AffBin}], +parse_aff_users([#xmlel{ name = <<"user">>, attrs = #{<<"affiliation">> := AffBin}, children = [ #xmlcdata{ content = JIDBin } ] } | RItemsEls], AffUsersAcc) -> #jid{} = JID = jid:from_binary(JIDBin), @@ -246,7 +241,7 @@ parse_blocking_list(ItemsEls) -> {ok, [blocking_item()]} | {error, bad_request}. parse_blocking_list([], ItemsAcc) -> {ok, ItemsAcc}; -parse_blocking_list([#xmlel{ name = WhatBin, attrs = [{<<"action">>, ActionBin}], +parse_blocking_list([#xmlel{ name = WhatBin, attrs = #{<<"action">> := ActionBin}, children = [ #xmlcdata{ content = JIDBin } ] } | RItemsEls], ItemsAcc) -> #jid{} = JID = jid:from_binary(JIDBin), @@ -270,9 +265,9 @@ encode_iq({get, #disco_info{ id = ID }}, Sender, RoomJID, _RoomBin, _HandleFun, encode_iq({get, #disco_items{ rooms = Rooms, id = ID, rsm = RSMOut }}, _Sender, _RoomJID, _RoomBin, _HandleFun, _Acc) -> DiscoEls = [ #xmlel{ name = <<"item">>, - attrs = [{<<"jid">>, <>}, - {<<"name">>, RoomName}, - {<<"version">>, RoomVersion}] } + attrs = #{<<"jid">> => <>, + <<"name">> => RoomName, + <<"version">> => RoomVersion} } || {{RoomU, RoomS}, RoomName, RoomVersion} <- Rooms ], {reply, ?NS_DISCO_ITEMS, jlib:rsm_encode(RSMOut) ++ DiscoEls, ID}; encode_iq({get, #config{ prev_version = SameVersion, version = SameVersion, id = ID }}, @@ -306,11 +301,9 @@ encode_iq({get, #info{ version = Version } = Info}, {reply, ?NS_MUC_LIGHT_INFO, InfoEls, Info#info.id}; encode_iq({set, #affiliations{} = Affs, OldAffUsers, NewAffUsers}, _Sender, RoomJID, RoomBin, HandleFun, Acc) -> - Attrs = [ - {<<"id">>, Affs#affiliations.id}, - {<<"type">>, <<"groupchat">>}, - {<<"from">>, RoomBin} - ], + Attrs = #{<<"id">> => Affs#affiliations.id, + <<"type">> => <<"groupchat">>, + <<"from">> => RoomBin}, AllAffsEls = [ aff_user_to_el(AffUser) || AffUser <- Affs#affiliations.aff_users ], VersionEl = kv_to_el(<<"version">>, Affs#affiliations.version), @@ -337,11 +330,9 @@ encode_iq({set, #blocking{ id = ID }}, {reply, ID}; encode_iq({set, #create{} = Create, UniqueRequested}, _Sender, RoomJID, RoomBin, HandleFun, Acc) -> - Attrs = [ - {<<"id">>, Create#create.id}, - {<<"type">>, <<"groupchat">>}, - {<<"from">>, RoomBin} - ], + Attrs = #{<<"id">> => Create#create.id, + <<"type">> => <<"groupchat">>, + <<"from">> => RoomBin}, VersionEl = kv_to_el(<<"version">>, Create#create.version), bcast_aff_messages(RoomJID, [], Create#create.aff_users, Attrs, VersionEl, [], HandleFun), @@ -363,18 +354,16 @@ encode_iq({set, #create{} = Create, UniqueRequested}, {reply, ResFromJID, ResFromBin, <<>>, undefined, Create#create.id}; encode_iq({set, #destroy{ id = ID }, AffUsers}, _Sender, RoomJID, RoomBin, HandleFun, _Acc) -> - Attrs = [ - {<<"id">>, ID}, - {<<"type">>, <<"groupchat">>}, - {<<"from">>, RoomBin} - ], + Attrs = #{<<"id">> => ID, + <<"type">> => <<"groupchat">>, + <<"from">> => RoomBin}, lists:foreach( fun({{U, S}, _}) -> NoneAffEnveloped = msg_envelope(?NS_MUC_LIGHT_AFFILIATIONS, [aff_user_to_el({{U, S}, none})]), DestroyEnveloped = [ #xmlel{ name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_MUC_LIGHT_DESTROY}] } + attrs = #{<<"xmlns">> => ?NS_MUC_LIGHT_DESTROY} } | NoneAffEnveloped ], msg_to_aff_user(RoomJID, U, S, Attrs, DestroyEnveloped, HandleFun) end, AffUsers), @@ -396,11 +385,9 @@ encode_iq({set, #config{} = Config, AffUsers}, {reply, Config#config.id}. encode_set_config(Config, RoomBin) -> - Attrs = [ - {<<"id">>, Config#config.id}, - {<<"type">>, <<"groupchat">>}, - {<<"from">>, RoomBin} - ], + Attrs = #{<<"id">> => Config#config.id, + <<"type">> => <<"groupchat">>, + <<"from">> => RoomBin}, ConfigEls = [ kv_to_el(ConfigField) || ConfigField <- Config#config.raw_config ], ConfigNotif = [ kv_to_el(<<"prev-version">>, Config#config.prev_version), kv_to_el(<<"version">>, Config#config.version) @@ -417,13 +404,13 @@ identity() -> -spec aff_user_to_el(aff_user()) -> exml:element(). aff_user_to_el({User, Aff}) -> #xmlel{ name = <<"user">>, - attrs = [{<<"affiliation">>, mod_muc_light_utils:aff2b(Aff)}], + attrs = #{<<"affiliation">> => mod_muc_light_utils:aff2b(Aff)}, children = [#xmlcdata{ content = jid:to_binary(User) }] }. -spec blocking_to_el(blocking_item()) -> exml:element(). blocking_to_el({What, Action, Who}) -> #xmlel{ name = what2b(What), - attrs = [{<<"action">>, action2b(Action)}], + attrs = #{<<"action">> => action2b(Action)}, children = [#xmlcdata{ content = jid:to_binary(Who) }] }. -spec kv_to_el({binary(), binary()}) -> exml:element(). @@ -436,18 +423,18 @@ kv_to_el(Key, Value) -> -spec msg_envelope(XMLNS :: binary(), Children :: [jlib:xmlch()]) -> [exml:element()]. msg_envelope(XMLNS, Children) -> - [ #xmlel{ name = <<"x">>, attrs = [{<<"xmlns">>, XMLNS}], children = Children }, + [ #xmlel{ name = <<"x">>, attrs = #{<<"xmlns">> => XMLNS}, children = Children }, #xmlel{ name = <<"body">> } ]. -spec inject_prev_version(IQChildren :: [jlib:xmlch()], PrevVersion :: binary()) -> [jlib:xmlch()]. -inject_prev_version([#xmlel{ name = <<"x">>, attrs = [{<<"xmlns">>, ?NS_MUC_LIGHT_AFFILIATIONS}], +inject_prev_version([#xmlel{ name = <<"x">>, attrs = #{<<"xmlns">> := ?NS_MUC_LIGHT_AFFILIATIONS}, children = Items} = XEl | REls], PrevVersion) -> [XEl#xmlel{ children = [kv_to_el(<<"prev-version">>, PrevVersion) | Items] } | REls]; inject_prev_version([El | REls], PrevVersion) -> [El | inject_prev_version(REls, PrevVersion)]. -spec bcast_aff_messages(From :: jid:jid(), OldAffUsers :: aff_users(), - NewAffUsers :: aff_users(), Attrs :: [{binary(), binary()}], + NewAffUsers :: aff_users(), Attrs :: exml:attrs(), VersionEl :: exml:element(), Children :: [jlib:xmlch()], HandleFun :: mod_muc_light_codec_backend:encoded_packet_handler()) -> ok. bcast_aff_messages(_, [], [], _, _, _, _) -> @@ -471,19 +458,19 @@ bcast_aff_messages(From, OldAffUsers, [{{ToU, ToS}, _} = AffUser | RNewAffUsers] bcast_aff_messages(From, OldAffUsers, RNewAffUsers, Attrs, VersionEl, Children, HandleFun). -spec msg_to_leaving_user(From :: jid:jid(), User :: jid:simple_bare_jid(), - Attrs :: [{binary(), binary()}], + Attrs :: exml:attrs(), HandleFun :: mod_muc_light_codec_backend:encoded_packet_handler()) -> ok. msg_to_leaving_user(From, {ToU, ToS} = User, Attrs, HandleFun) -> NotifForLeaving = msg_envelope(?NS_MUC_LIGHT_AFFILIATIONS, [ aff_user_to_el({User, none}) ]), msg_to_aff_user(From, ToU, ToS, Attrs, NotifForLeaving, HandleFun). -spec msg_to_aff_user(From :: jid:jid(), ToU :: jid:luser(), ToS :: jid:lserver(), - Attrs :: [{binary(), binary()}], Children :: [jlib:xmlch()], + Attrs :: exml:attrs(), Children :: [jlib:xmlch()], HandleFun :: mod_muc_light_codec_backend:encoded_packet_handler()) -> ok. msg_to_aff_user(From, ToU, ToS, Attrs, Children, HandleFun) -> To = jid:make_noprep(ToU, ToS, <<>>), ToBin = jid:to_binary({ToU, ToS, <<>>}), - Packet = #xmlel{ name = <<"message">>, attrs = [{<<"to">>, ToBin} | Attrs], + Packet = #xmlel{ name = <<"message">>, attrs = Attrs#{<<"to">> => ToBin}, children = Children }, HandleFun(From, To, Packet). @@ -497,12 +484,10 @@ jids_from_room_with_resource(RoomJID, Resource) -> -spec make_iq_result(FromBin :: binary(), ToBin :: binary(), ID :: binary(), XMLNS :: binary(), Els :: [jlib:xmlch()] | undefined) -> exml:element(). make_iq_result(FromBin, ToBin, ID, XMLNS, Els) -> - Attrs = [ - {<<"from">>, FromBin}, - {<<"to">>, ToBin}, - {<<"id">>, ID}, - {<<"type">>, <<"result">>} - ], + Attrs = #{<<"from">> => FromBin, + <<"to">> => ToBin, + <<"id">> => ID, + <<"type">> => <<"result">>}, Query = make_query_el(XMLNS, Els), #xmlel{ name = <<"iq">>, attrs = Attrs, children = Query }. @@ -510,7 +495,7 @@ make_iq_result(FromBin, ToBin, ID, XMLNS, Els) -> make_query_el(_, undefined) -> []; make_query_el(XMLNS, Els) -> - [#xmlel{ name = <<"query">>, attrs = [{<<"xmlns">>, XMLNS}], children = Els }]. + [#xmlel{ name = <<"query">>, attrs = #{<<"xmlns">> => XMLNS}, children = Els }]. %%==================================================================== %% Common helpers and internal functions diff --git a/src/offline/mod_offline.erl b/src/offline/mod_offline.erl index 7a91de901cc..abacc68bf84 100644 --- a/src/offline/mod_offline.erl +++ b/src/offline/mod_offline.erl @@ -387,7 +387,7 @@ patch_offline_message(Packet) -> x_elem(ID) -> #xmlel{ name = <<"x">>, - attrs = [{<<"xmlns">>, ?NS_EVENT}], + attrs = #{<<"xmlns">> => ?NS_EVENT}, children = [ID, #xmlel{name = <<"offline">>}]}. %% Check if the packet has subelements about XEP-0022, XEP-0085 or other diff --git a/src/offline/mod_offline_chatmarkers.erl b/src/offline/mod_offline_chatmarkers.erl index aaaffc6aed7..5045e3f632b 100644 --- a/src/offline/mod_offline_chatmarkers.erl +++ b/src/offline/mod_offline_chatmarkers.erl @@ -167,8 +167,8 @@ build_one2one_chatmarker_msg(Acc, CM) -> #{from := From, to := To, thread := Thread, type := Type, id := Id, timestamp := TS} = CM, Children = thread(Thread) ++ marker(Type, Id), - Attributes = [{<<"from">>, jid:to_binary(From)}, - {<<"to">>, jid:to_binary(To)}], + Attributes = #{<<"from">> => jid:to_binary(From), + <<"to">> => jid:to_binary(To)}, Packet = #xmlel{name = <<"message">>, attrs = Attributes, children = Children}, make_route_item(Acc, From, To, TS, Packet). @@ -179,9 +179,9 @@ build_room_chatmarker_msg(Acc, To, CM) -> From = jid:make(Room#jid.luser, Room#jid.lserver, FromUserBin), FromBin = jid:to_binary(From), Children = thread(Thread) ++ marker(Type, Id), - Attributes = [{<<"from">>, FromBin}, - {<<"to">>, jid:to_binary(To)}, - {<<"type">>, <<"groupchat">>}], + Attributes = #{<<"from">> => FromBin, + <<"to">> => jid:to_binary(To), + <<"type">> => <<"groupchat">>}, Packet = #xmlel{name = <<"message">>, attrs = Attributes, children = Children}, make_route_item(Acc, From, To, TS, Packet). @@ -193,10 +193,10 @@ make_route_item(Acc, From, To, TS, Packet) -> marker(Type, Id) -> [#xmlel{name = atom_to_binary(Type, latin1), - attrs = [{<<"xmlns">>, <<"urn:xmpp:chat-markers:0">>}, - {<<"id">>, Id}], children = []}]. + attrs = #{<<"xmlns">> => <<"urn:xmpp:chat-markers:0">>, + <<"id">> => Id}}]. thread(undefined) -> []; thread(Thread) -> - [#xmlel{name = <<"thread">>, attrs = [], + [#xmlel{name = <<"thread">>, children = [#xmlcdata{content = Thread}]}]. diff --git a/src/privacy/mod_blocking.erl b/src/privacy/mod_blocking.erl index 497c0973f51..9180c1cc018 100644 --- a/src/privacy/mod_blocking.erl +++ b/src/privacy/mod_blocking.erl @@ -315,17 +315,17 @@ broadcast_blocking_command(Acc, LUser, LServer, UserList, Changed, Type) -> blocking_query_response(Lst) -> #xmlel{ name = <<"blocklist">>, - attrs = [{<<"xmlns">>, ?NS_BLOCKING}], + attrs = #{<<"xmlns">> => ?NS_BLOCKING}, children = [#xmlel{name= <<"item">>, - attrs = [{<<"jid">>, jid:to_binary(J#listitem.value)}]} || J <- Lst]}. + attrs = #{<<"jid">> => jid:to_binary(J#listitem.value)}} || J <- Lst]}. -spec blocking_stanza([binary()], binary()) -> exml:element(). blocking_stanza(JIDs, Name) -> #xmlel{name = Name, - attrs = [{<<"xmlns">>, ?NS_BLOCKING}], + attrs = #{<<"xmlns">> => ?NS_BLOCKING}, children = lists:map( fun(JID) -> - #xmlel{name = <<"item">>, attrs = [{<<"jid">>, JID}]} + #xmlel{name = <<"item">>, attrs = #{<<"jid">> => JID}} end, JIDs)}. -spec blocking_iq(exml:element()) -> jlib:iq(). diff --git a/src/privacy/mod_privacy.erl b/src/privacy/mod_privacy.erl index 1e4a4fed5c8..1544c483635 100644 --- a/src/privacy/mod_privacy.erl +++ b/src/privacy/mod_privacy.erl @@ -316,7 +316,7 @@ maybe_update_presence(Acc, StateData, OldList, NewList) -> send_unavail_if_newly_blocked(Acc, Jid, ContactJID, OldList, NewList, StateData) -> Packet = #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, <<"unavailable">>}]}, + attrs = #{<<"type">> => <<"unavailable">>}}, %% WARNING: we can not use accumulator to cache privacy check result - this is %% the only place where the list to check against changes {OldResult, _} = p_privacy_check_packet(Packet, Jid, ContactJID, out, OldList, StateData), @@ -380,9 +380,9 @@ privacy_list_push_iq(PrivListName) -> #iq{type = set, xmlns = ?NS_PRIVACY, id = <<"push", (mongoose_bin:gen_from_crypto())/binary>>, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_PRIVACY}], + attrs = #{<<"xmlns">> => ?NS_PRIVACY}, children = [#xmlel{name = <<"list">>, - attrs = [{<<"name">>, PrivListName}]}]}]}. + attrs = #{<<"name">> => PrivListName}}]}]}. -spec disco_local_features(mongoose_disco:feature_acc(), map(), map()) -> {ok, mongoose_disco:feature_acc()}. @@ -844,12 +844,12 @@ add_item(Item, Items) -> empty_list_names_query() -> #xmlel{ name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_PRIVACY}]}. + attrs = #{<<"xmlns">> => ?NS_PRIVACY}}. list_names_query(Active, Default, ListNames) -> #xmlel{ name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_PRIVACY}], + attrs = #{<<"xmlns">> => ?NS_PRIVACY}, children = list_names(Active, Default, ListNames)}. list_names(Active, Default, ListNames) -> @@ -858,16 +858,16 @@ list_names(Active, Default, ListNames) -> [list_name(<<"list">>, ListName) || ListName <- ListNames]. list_name(Type, Name) -> - #xmlel{name = Type, attrs = [{<<"name">>, Name}]}. + #xmlel{name = Type, attrs = #{<<"name">> => Name}}. list_query_result(Name, LItems) -> #xmlel{ name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_PRIVACY}], + attrs = #{<<"xmlns">> => ?NS_PRIVACY}, children = [ #xmlel{ name = <<"list">>, - attrs = [{<<"name">>, Name}], + attrs = #{<<"name">> => Name}, children = LItems}]}. item_to_xml(Item) -> @@ -879,13 +879,13 @@ item_to_xml(Item) -> item_to_xml_attrs(Item=#listitem{type=none}) -> item_to_xml_attrs1(Item); item_to_xml_attrs(Item=#listitem{type=Type, value=Value}) -> - [{<<"type">>, type_to_binary(Type)}, - {<<"value">>, value_to_binary(Type, Value)} - | item_to_xml_attrs1(Item)]. + Attrs = item_to_xml_attrs1(Item), + Attrs#{<<"type">> => type_to_binary(Type), + <<"value">> => value_to_binary(Type, Value)}. item_to_xml_attrs1(#listitem{action=Action, order=Order}) -> - [{<<"action">>, action_to_binary(Action)}, - {<<"order">>, order_to_binary(Order)}]. + #{<<"action">> => action_to_binary(Action), + <<"order">> => order_to_binary(Order)}. item_to_xml_children(#listitem{match_all=true}) -> []; diff --git a/src/pubsub/mod_pubsub.erl b/src/pubsub/mod_pubsub.erl index b7f18d05e29..79387cbc440 100644 --- a/src/pubsub/mod_pubsub.erl +++ b/src/pubsub/mod_pubsub.erl @@ -94,9 +94,9 @@ %% general helpers for plugins -export([subscription_to_string/1, affiliation_to_string/1, string_to_subscription/1, string_to_affiliation/1, - extended_error/2, extended_error/3, service_jid/1, - tree/1, plugin/1, plugin_call/3, host/2, serverhost/1, - host_to_host_type/1]). + extended_error/2, service_jid/1, tree/1, plugin/1, + plugin_call/3, serverhost/1, host_to_host_type/1, + host/2]). %% API and gen_server callbacks -export([start_link/2, start/2, stop/1, deps/2, init/1, @@ -132,7 +132,6 @@ default_host/0, delete_item/4, delete_node/3, - extended_error/3, get_cached_item/2, get_item/3, get_items/2, @@ -1082,7 +1081,7 @@ do_route(Acc, ServerHost, Access, Plugins, Host, From, Res = IQ#iq{type = result, sub_el = [#xmlel{name = <<"vCard">>, - attrs = [{<<"xmlns">>, XMLNS}], + attrs = #{<<"xmlns">> => XMLNS}, children = iq_get_vcard(Lang)}]}, ejabberd_router:route(To, From, Acc, jlib:iq_to_xml(Res)); #iq{type = set, xmlns = ?NS_COMMANDS} = IQ -> @@ -1132,15 +1131,15 @@ do_route(Acc, _ServerHost, _Access, _Plugins, _Host, From, To, Packet) -> command_disco_info(_Host, ?NS_COMMANDS, _From) -> IdentityEl = #xmlel{name = <<"identity">>, - attrs = [{<<"category">>, <<"automation">>}, - {<<"type">>, <<"command-list">>}]}, + attrs = #{<<"category">> => <<"automation">>, + <<"type">> => <<"command-list">>}}, {result, [IdentityEl]}; command_disco_info(_Host, ?NS_PUBSUB_GET_PENDING, _From) -> IdentityEl = #xmlel{name = <<"identity">>, - attrs = [{<<"category">>, <<"automation">>}, - {<<"type">>, <<"command-node">>}]}, + attrs = #{<<"category">> => <<"automation">>, + <<"type">> => <<"command-node">>}}, FeaturesEl = #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_COMMANDS}]}, + attrs = #{<<"var">> => ?NS_COMMANDS}}, {result, [IdentityEl, FeaturesEl]}. node_disco_info(Host, Node, From) -> @@ -1153,12 +1152,12 @@ node_disco_info(Host, Node, _From, _Identity, _Features) -> _ -> <<"leaf">> end, I = #xmlel{name = <<"identity">>, - attrs = [{<<"category">>, <<"pubsub">>}, - {<<"type">>, NodeType}]}, + attrs = #{<<"category">> => <<"pubsub">>, + <<"type">> => NodeType}}, F = [#xmlel{name = <<"feature">>, - attrs = [{<<"var">>, ?NS_PUBSUB}]} + attrs = #{<<"var">> => ?NS_PUBSUB}} | [#xmlel{name = <<"feature">>, - attrs = [{<<"var">>, feature(F)}]} + attrs = #{<<"var">> => feature(F)}} || F <- plugin_features(Type)]], {result, [I | F]} end, @@ -1199,23 +1198,22 @@ iq_disco_info(ServerHost, Host, SNode, From, Lang) -> iq_disco_items(Host, <<>>, From, _RSM) -> {result, lists:map(fun (#pubsub_node{nodeid = {_, SubNode}, options = Options}) -> - Attrs = case get_option(Options, title) of - false -> - [{<<"jid">>, Host} - | node_attr(SubNode)]; - [Title] -> - [{<<"jid">>, Host}, - {<<"name">>, Title} - | node_attr(SubNode)] + Attrs1 = node_attr(SubNode), + Attrs2 = case get_option(Options, title) of + false -> + Attrs1#{<<"jid">> => Host}; + [Title] -> + Attrs1#{<<"jid">> => Host, + <<"name">> => Title} end, - #xmlel{name = <<"item">>, attrs = Attrs} + #xmlel{name = <<"item">>, attrs = Attrs2} end, tree_action(Host, get_subnodes, [Host, <<>>, From]))}; iq_disco_items(Host, ?NS_COMMANDS, _From, _RSM) -> {result, [#xmlel{name = <<"item">>, - attrs = [{<<"jid">>, Host}, - {<<"node">>, ?NS_PUBSUB_GET_PENDING}, - {<<"name">>, <<"Get Pending">>}]}]}; + attrs = #{<<"jid">> => Host, + <<"node">> => ?NS_PUBSUB_GET_PENDING, + <<"name">> => <<"Get Pending">>}}]}; iq_disco_items(_Host, ?NS_PUBSUB_GET_PENDING, _From, _RSM) -> {result, []}; iq_disco_items(Host, Item, From, RSM) -> @@ -1241,23 +1239,22 @@ iq_disco_items_transaction(Host, From, Node, RSM, _ -> {[], none} end, Nodes = lists:map(fun (#pubsub_node{nodeid = {_, SubNode}, options = SubOptions}) -> - Attrs = case get_option(SubOptions, title) of - false -> - [{<<"jid">>, Host} - | node_attr(SubNode)]; - [Title] -> - [{<<"jid">>, Host}, - {<<"name">>, Title} - | node_attr(SubNode)] - end, - #xmlel{name = <<"item">>, attrs = Attrs} + Attrs1 = node_attr(SubNode), + Attrs2 = case get_option(SubOptions, title) of + false -> + Attrs1#{<<"jid">> => Host}; + [Title] -> + Attrs1#{<<"jid">> => Host, + <<"name">> => Title} + end, + #xmlel{name = <<"item">>, attrs = Attrs2} end, tree_call(Host, get_subnodes, [Host, Node, From])), Items = lists:map(fun (#pubsub_item{itemid = {RN, _}}) -> {result, Name} = node_call(Type, get_item_name, [Host, Node, RN]), #xmlel{name = <<"item">>, - attrs = [{<<"jid">>, Host}, {<<"name">>, Name}]} + attrs = #{<<"jid">> => Host, <<"name">> => Name}} end, NodeItems), {result, Nodes ++ Items ++ jlib:rsm_encode(RsmOut)}. @@ -1284,11 +1281,11 @@ iq_sm(From, To, Acc, #iq{type = Type, sub_el = SubEl, xmlns = XMLNS, lang = Lang iq_get_vcard(Lang) -> Desc = <<(translate:translate(Lang, <<"ejabberd Publish-Subscribe module">>))/binary, "\nCopyright (c) 2004-2015 ProcessOne">>, - [#xmlel{name = <<"FN">>, attrs = [], + [#xmlel{name = <<"FN">>, children = [#xmlcdata{content = <<"ejabberd/mod_pubsub">>}]}, - #xmlel{name = <<"URL">>, attrs = [], + #xmlel{name = <<"URL">>, children = [#xmlcdata{content = ?MONGOOSE_URI}]}, - #xmlel{name = <<"DESC">>, attrs = [], + #xmlel{name = <<"DESC">>, children = [#xmlcdata{content = Desc}]}]. -spec iq_pubsub(Host :: mod_pubsub:host(), @@ -1443,7 +1440,8 @@ iq_pubsub_set_create(Host, Node, From, case lists:member(Type, Plugins) of false -> {error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, <<"create-nodes">>)}; + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"create-nodes">>)}; true -> create_node(Host, ServerHost, Node, From, Type, Access, Config) end. @@ -1726,7 +1724,7 @@ send_authorization_request(#pubsub_node{nodeid = {Host, Node}, owners = Owners}, Form = mongoose_data_forms:form(#{title => Title, instructions => Instructions, ns => ?NS_PUBSUB_SUB_AUTH, fields => Fields}), Stanza = #xmlel{name = <<"message">>, - attrs = [{<<"id">>, mongoose_bin:gen_from_crypto()}], + attrs = #{<<"id">> => mongoose_bin:gen_from_crypto()}, children = [Form]}, lists:foreach(fun(Owner) -> ejabberd_router:route(service_jid(Host), jid:make(Owner), Stanza) @@ -1747,17 +1745,16 @@ find_authorization_response(El) -> %% @doc Send a message to JID with the supplied Subscription send_authorization_approval(Host, JID, SNode, Subscription) -> - SubAttrs = case Subscription of - %{S, SID} -> - % [{<<"subscription">>, subscription_to_string(S)}, - % {<<"subid">>, SID}]; - S -> - [{<<"subscription">>, subscription_to_string(S)}] - end, + Attrs1 = node_attr(SNode), + Attrs2 = case Subscription of + % {S, SID} -> + % Attrs1#{<<"subscription">> => subscription_to_string(S), + % <<"subid">> => SID}; + S -> + Attrs1#{<<"subscription">> => subscription_to_string(S)} + end, Stanza = event_stanza(<<"subscription">>, - [{<<"jid">>, jid:to_binary(JID)} - | node_attr(SNode)] - ++ SubAttrs), + Attrs2#{<<"jid">> => jid:to_binary(JID)}), ejabberd_router:route(service_jid(Host), JID, Stanza). handle_authorization_response(Acc, Host, From, To, Packet, XFields) -> @@ -1901,7 +1898,7 @@ create_node(Host, ServerHost, <<>>, Owner, Type, Access, Configuration) -> case create_node(Host, ServerHost, Node, Owner, Type, Access, Configuration) of {result, _} -> {result, [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], + attrs = #{<<"xmlns">> => ?NS_PUBSUB}, children = [#xmlel{name = <<"create">>, attrs = node_attr(Node)}]}]}; Error -> @@ -2002,7 +1999,7 @@ create_node_reply(_Node, Result) -> create_node_make_reply(Node) -> [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], + attrs = #{<<"xmlns">> => ?NS_PUBSUB}, children = [#xmlel{name = <<"create">>, attrs = node_attr(Node)}]}]. @@ -2127,7 +2124,8 @@ subscribe_node_transaction(Host, SubOpts, From, Subscriber, PubSubNode) -> subscribe_node_transaction_step1(Host, SubOpts, From, Subscriber, PubSubNode, Features) -> case lists:member(<<"subscribe">>, Features) of false -> - {error, extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, <<"subscribe">>)}; + {error, unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"subscribe">>)}; true -> subscribe_node_transaction_step2(Host, SubOpts, From, Subscriber, PubSubNode, Features) end. @@ -2135,7 +2133,8 @@ subscribe_node_transaction_step1(Host, SubOpts, From, Subscriber, PubSubNode, Fe subscribe_node_transaction_step2(Host, SubOpts, From, Subscriber, PubSubNode, Features) -> case get_option(PubSubNode#pubsub_node.options, subscribe) of false -> - {error, extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, <<"subscribe">>)}; + {error, unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"subscribe">>)}; true -> subscribe_node_transaction_step3(Host, SubOpts, From, Subscriber, PubSubNode, Features) end. @@ -2144,7 +2143,8 @@ subscribe_node_transaction_step3(Host, SubOpts, From, Subscriber, PubSubNode, Fe case {SubOpts /= [], lists:member(<<"subscription-options">>, Features)} of {true, false} -> {error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, <<"subscription-options">>)}; + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"subscription-options">>)}; _ -> subscribe_node_transaction_step4(Host, SubOpts, From, Subscriber, PubSubNode) end. @@ -2187,20 +2187,19 @@ count_subscribed(NodeSubs) -> end, 0, NodeSubs). subscribe_node_reply(Subscriber, Node, {subscribed, SubId}) -> - SubAttrs = [{<<"subscription">>, subscription_to_string(subscribed)}, - {<<"subid">>, SubId}, {<<"node">>, Node}], + SubAttrs = #{<<"subscription">> => subscription_to_string(subscribed), + <<"subid">> => SubId, <<"node">> => Node}, subscribe_node_reply(Subscriber, SubAttrs); subscribe_node_reply(Subscriber, Node, Subscription) -> - SubAttrs = [{<<"subscription">>, subscription_to_string(Subscription)}, - {<<"node">>, Node}], + SubAttrs = #{<<"subscription">> => subscription_to_string(Subscription), + <<"node">> => Node}, subscribe_node_reply(Subscriber, SubAttrs). subscribe_node_reply(Subscriber, SubAttrs) -> [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], + attrs = #{<<"xmlns">> => ?NS_PUBSUB}, children = [#xmlel{name = <<"subscription">>, - attrs = [{<<"jid">>, jid:to_binary(Subscriber)} - | SubAttrs]}]}]. + attrs = SubAttrs#{<<"jid">> => jid:to_binary(Subscriber)}}]}]. %% @doc

Unsubscribe JID from the Node.

%%

There are several reasons why the unsubscribe request might fail:

@@ -2275,10 +2274,11 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload, Access, Publish Errors = [ %% [{Condition :: boolean(), Reason :: term()}] {not PublishFeature, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, <<"publish">>)}, + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"publish">>)}, {not PubOptsFeature andalso PublishOptions /= undefined, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, - <<"publish-options">>)}, + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"publish-options">>)}, {PayloadSize > PayloadMaxSize, extended_error(mongoose_xmpp_errors:not_acceptable(), <<"payload-too-big">>)}, {(PayloadCount == 0) and (Payload == []), @@ -2303,7 +2303,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload, Access, Publish end end, Reply = [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], + attrs = #{<<"xmlns">> => ?NS_PUBSUB}, children = [#xmlel{name = <<"publish">>, attrs = node_attr(Node), children = [#xmlel{name = <<"item">>, attrs = item_attr(ItemId)}]}]}], @@ -2363,9 +2363,9 @@ autocreate_if_supported_and_publish(Host, ServerHost, Node, Publisher, case create_node(Host, ServerHost, Node, Publisher, Type, Access, PublishOptions) of {result, [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], + attrs = #{<<"xmlns">> := ?NS_PUBSUB}, children = [#xmlel{name = <<"create">>, - attrs = [{<<"node">>, NewNode}]}]}]} -> + attrs = #{<<"node">> := NewNode}}]}]} -> publish_item(Host, ServerHost, NewNode, Publisher, ItemId, Payload); _ -> {error, ErrorItemNotFound} @@ -2431,11 +2431,13 @@ delete_item_transaction(Publisher, ItemId, node_call(Type, delete_item, [Nidx, Publisher, PublishModel, ItemId]); false -> {error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, <<"delete-items">>)} + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"delete-items">>)} end; false -> {error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, <<"persistent-items">>)} + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"persistent-items">>)} end. %% @doc

Delete all items of specified node owned by JID.

@@ -2479,13 +2481,16 @@ purge_node_transaction(Owner, #pubsub_node{options = Options, type = Type, id = get_option(Options, persist_items)} of {false, _, _} -> {error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, <<"purge-nodes">>)}; + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"purge-nodes">>)}; {_, false, _} -> {error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, <<"persistent-items">>)}; + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"persistent-items">>)}; {_, _, false} -> {error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, <<"persistent-items">>)}; + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"persistent-items">>)}; _ -> node_call(Type, purge_node, [Nidx, Owner]) end. @@ -2524,7 +2529,7 @@ get_items_with_limit(Host, Node, From, SubId, ItemIds, RSM, MaxItems) -> {result, {_, {Items, RsmOut}}} -> {result, [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], + attrs = #{<<"xmlns">> => ?NS_PUBSUB}, children = [#xmlel{name = <<"items">>, attrs = node_attr(Node), children = items_els(Items)} @@ -2541,10 +2546,12 @@ get_items_transaction(Host, From, RSM, SubId, lists:member(<<"persistent-items">>, Features)} of {false, _} -> {error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, <<"retrieve-items">>)}; + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"retrieve-items">>)}; {_, false} -> {error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, <<"persistent-items">>)}; + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"persistent-items">>)}; _ -> AccessModel = get_option(Options, access_model), AllowedGroups = get_option(Options, roster_groups_allowed, []), @@ -2661,8 +2668,8 @@ get_affiliations(Host, Node, JID, #{plugins := Plugins}) when is_list(Plugins) - {Status, [Affs | Acc]}; false -> {{error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), - unsupported, <<"retrieve-affiliations">>)}, + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"retrieve-affiliations">>)}, Acc} end end, {ok, []}, Plugins), @@ -2673,17 +2680,17 @@ get_affiliations(Host, Node, JID, #{plugins := Plugins}) when is_list(Plugins) - []; ({#pubsub_node{nodeid = {_, NodeId}}, Aff}) when Node == <<>> orelse Node == NodeId -> + Attrs = node_attr(NodeId), [#xmlel{name = <<"affiliation">>, - attrs = [{<<"affiliation">>, affiliation_to_string(Aff)} - | node_attr(NodeId)]}]; + attrs = Attrs#{<<"affiliation">> => affiliation_to_string(Aff)}}]; (_) -> [] end, lists:usort(lists:flatten(Affs))), {result, [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], - children = [#xmlel{name = <<"affiliations">>, attrs = [], + attrs = #{<<"xmlns">> => ?NS_PUBSUB}, + children = [#xmlel{name = <<"affiliations">>, children = Entities}]}]}; {Error, _} -> Error @@ -2703,12 +2710,12 @@ get_affiliations(Host, Node, JID) -> ({AJID, Aff}) -> [#xmlel{ name = <<"affiliation">>, - attrs = [{<<"jid">>, jid:to_binary(AJID)}, - {<<"affiliation">>, affiliation_to_string(Aff)}]}] + attrs = #{<<"jid">> => jid:to_binary(AJID), + <<"affiliation">> => affiliation_to_string(Aff)}}] end, Affs), {result, [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB_OWNER}], + attrs = #{<<"xmlns">> => ?NS_PUBSUB_OWNER}, children = [#xmlel{name = <<"affiliations">>, attrs = node_attr(Node), children = Entities}]}]}; Error -> @@ -2727,7 +2734,8 @@ get_affiliations_transaction(JID, #pubsub_node{type = Type, id = Nidx}) -> end; false -> {error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, <<"modify-affiliations">>)} + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"modify-affiliations">>)} end. -spec set_affiliations( @@ -2782,14 +2790,14 @@ set_affiliations_transaction(Host, Owner, case sets:size(OwnersDryRun) of 0 -> OwnersPayload = [ #xmlel{ name = <<"affiliation">>, - attrs = [{<<"jid">>, jid:to_binary(Unchanged)}, - {<<"affiliation">>, <<"owner">>}] } + attrs = #{<<"jid">> => jid:to_binary(Unchanged), + <<"affiliation">> => <<"owner">>} } || Unchanged <- Owners ], AffiliationsPayload = #xmlel{ name = <<"affiliations">>, - attrs = [{<<"node">>, NodeId}], + attrs = #{<<"node">> => NodeId}, children = OwnersPayload }, NewPubSubPayload = #xmlel{ name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB_OWNER}], + attrs = #{<<"xmlns">> => ?NS_PUBSUB_OWNER}, children = [AffiliationsPayload] }, {error, {mongoose_xmpp_errors:not_acceptable(), [NewPubSubPayload]}}; _ -> @@ -2841,8 +2849,8 @@ get_options_transaction(Node, JID, SubId, Lang, #pubsub_node{type = Type, id = N get_sub_options_xml(JID, Lang, Node, Nidx, SubId, Type); false -> {error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), - unsupported, <<"subscription-options">>)} + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"subscription-options">>)} end. % TODO: Support Lang at some point again @@ -2870,13 +2878,13 @@ get_sub_options_xml(JID, _Lang, Node, Nidx, RequestedSubId, Type) -> make_and_wrap_sub_xform(Options, Node, Subscriber, SubId) -> {ok, XForm} = pubsub_form_utils:make_sub_xform(Options), + Attrs = node_attr(Node), OptionsEl = #xmlel{name = <<"options">>, - attrs = [{<<"jid">>, jid:to_binary(Subscriber)}, - {<<"subid">>, SubId} - | node_attr(Node)], + attrs = Attrs#{<<"jid">> => jid:to_binary(Subscriber), + <<"subid">> => SubId}, children = [XForm]}, PubSubEl = #xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], + attrs = #{<<"xmlns">> => ?NS_PUBSUB}, children = [OptionsEl]}, {result, PubSubEl}. @@ -2896,8 +2904,8 @@ set_options_transaction(JID, SubId, ConfigXForm, #pubsub_node{type = Type, id = validate_and_set_options_helper(ConfigXForm, JID, Nidx, SubId, Type); false -> {error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), - unsupported, <<"subscription-options">>)} + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"subscription-options">>)} end. validate_and_set_options_helper(ConfigXForm, JID, Nidx, SubId, Type) -> @@ -2953,9 +2961,8 @@ get_subscriptions(Host, Node, JID, #{plugins := Plugins}) when is_list(Plugins) {Status, [Subs | Acc]}; false -> {{error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), - unsupported, - <<"retrieve-subscriptions">>)}, + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"retrieve-subscriptions">>)}, Acc} end end, @@ -2966,8 +2973,8 @@ get_subscriptions(Host, Node, JID, #{plugins := Plugins}) when is_list(Plugins) lists:usort(lists:flatten(Subs))), {result, [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], - children = [#xmlel{name = <<"subscriptions">>, attrs = [], + attrs = #{<<"xmlns">> => ?NS_PUBSUB}, + children = [#xmlel{name = <<"subscriptions">>, children = Entities}]}]}; {Error, _} -> Error @@ -2977,14 +2984,12 @@ get_subscriptions(Host, Node, JID, #{plugins := Plugins}) when is_list(Plugins) subscription_to_xmlel({_, none}, _Node) -> []; subscription_to_xmlel({#pubsub_node{nodeid = {_, SubsNode}}, Sub}, <<>>) -> + Attrs = node_attr(SubsNode), [#xmlel{name = <<"subscription">>, - attrs = - [{<<"subscription">>, subscription_to_string(Sub)} - | node_attr(SubsNode)]}]; + attrs = Attrs#{<<"subscription">> => subscription_to_string(Sub)}}]; subscription_to_xmlel({#pubsub_node{nodeid = {_, SubsNode}}, Sub}, SubsNode) -> [#xmlel{name = <<"subscription">>, - attrs = - [{<<"subscription">>, subscription_to_string(Sub)}]}]; + attrs = #{<<"subscription">> => subscription_to_string(Sub)}}]; subscription_to_xmlel({#pubsub_node{nodeid = {_, _}}, _}, _) -> []; %% no idea how to trigger this one @@ -2992,32 +2997,28 @@ subscription_to_xmlel({_, none, _}, _Node) -> []; %% sometimes used by node_pep subscription_to_xmlel({#pubsub_node{nodeid = {_, SubsNode}}, Sub, SubId, SubJID}, <<>>) -> + Attrs = node_attr(SubsNode), [#xmlel{name = <<"subscription">>, - attrs = - [{<<"jid">>, jid:to_binary(SubJID)}, - {<<"subid">>, SubId}, - {<<"subscription">>, subscription_to_string(Sub)} - | node_attr(SubsNode)]}]; + attrs = Attrs#{<<"jid">> => jid:to_binary(SubJID), + <<"subid">> => SubId, + <<"subscription">> => subscription_to_string(Sub)}}]; subscription_to_xmlel({#pubsub_node{nodeid = {_, SubsNode}}, Sub, SubId, SubJID}, SubsNode) -> [#xmlel{name = <<"subscription">>, - attrs = - [{<<"jid">>, jid:to_binary(SubJID)}, - {<<"subid">>, SubId}, - {<<"subscription">>, subscription_to_string(Sub)}]}]; + attrs =#{<<"jid">> => jid:to_binary(SubJID), + <<"subid">> => SubId, + <<"subscription">> => subscription_to_string(Sub)}}]; subscription_to_xmlel({#pubsub_node{nodeid = {_, _}}, _, _, _}, _Node) -> []; %% used by node_flat (therefore by dag, hometree and push as well) subscription_to_xmlel({#pubsub_node{nodeid = {_, SubsNode}}, Sub, SubJID}, <<>>) -> + Attrs = node_attr(SubsNode), [#xmlel{name = <<"subscription">>, - attrs = - [{<<"jid">>, jid:to_binary(SubJID)}, - {<<"subscription">>, subscription_to_string(Sub)} - | node_attr(SubsNode)]}]; + attrs = Attrs#{<<"jid">> => jid:to_binary(SubJID), + <<"subscription">> => subscription_to_string(Sub)}}]; subscription_to_xmlel({#pubsub_node{nodeid = {_, SubsNode}}, Sub, SubJID}, SubsNode) -> [#xmlel{name = <<"subscription">>, - attrs = - [{<<"jid">>, jid:to_binary(SubJID)}, - {<<"subscription">>, subscription_to_string(Sub)}]}]; + attrs = #{<<"jid">> => jid:to_binary(SubJID), + <<"subscription">> => subscription_to_string(Sub)}}]; subscription_to_xmlel({#pubsub_node{nodeid = {_, _}}, _, _}, _Node) -> []. @@ -3030,14 +3031,14 @@ get_subscriptions(Host, Node, JID) -> []; ({AJID, Sub, SubId, _}) -> [#xmlel{name = <<"subscription">>, - attrs = - [{<<"jid">>, jid:to_binary(AJID)}, - {<<"subscription">>, subscription_to_string(Sub)}, - {<<"subid">>, SubId}]}] + attrs =#{ + <<"jid">> => jid:to_binary(AJID), + <<"subscription">> => subscription_to_string(Sub), + <<"subid">> => SubId}}] end, Subs), {result, [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB_OWNER}], + attrs = #{<<"xmlns">> => ?NS_PUBSUB_OWNER}, children = [#xmlel{name = <<"subscriptions">>, attrs = node_attr(Node), children = Entities}]}]}; @@ -3057,7 +3058,8 @@ get_subscriptions_transaction(JID, #pubsub_node{type = Type, id = Nidx}) -> end; false -> {error, - extended_error(mongoose_xmpp_errors:feature_not_implemented(), unsupported, <<"manage-subscriptions">>)} + unsupported_error(mongoose_xmpp_errors:feature_not_implemented(), + <<"manage-subscriptions">>)} end. get_subscriptions_for_send_last(Host, PType, [JID, LJID, BJID]) -> @@ -3125,14 +3127,14 @@ set_subscription_transaction(Host, Node, Nidx, Type, {JID, Sub, SubId}, Acc) -> end. notify_subscription_change(Host, Node, JID, Sub) -> + Attrs = node_attr(Node), SubscriptionEl = #xmlel{name = <<"subscription">>, - attrs = [{<<"jid">>, jid:to_binary(JID)}, - {<<"subscription">>, subscription_to_string(Sub)} - | node_attr(Node)]}, + attrs = Attrs#{<<"jid">> => jid:to_binary(JID), + <<"subscription">> => subscription_to_string(Sub)}}, PubSubEl = #xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB}], + attrs = #{<<"xmlns">> => ?NS_PUBSUB}, children = [SubscriptionEl]}, - Stanza = #xmlel{name = <<"message">>, attrs = [], children = [PubSubEl]}, + Stanza = #xmlel{name = <<"message">>, children = [PubSubEl]}, ejabberd_router:route(service_jid(Host), jid:make(JID), Stanza). -spec get_presence_and_roster_permissions(Host :: mod_pubsub:host(), @@ -3308,24 +3310,25 @@ items_event_stanza(Node, Items) -> Sec = erlang:convert_time_unit(ModifNow, microsecond, second), TString = calendar:system_time_to_rfc3339(Sec, [{offset, "Z"}]), [#xmlel{name = <<"delay">>, - attrs = [{<<"xmlns">>, ?NS_DELAY}, - {<<"from">>, jid:to_binary(ModifUSR)}, - {<<"stamp">>, list_to_binary(TString)}], - children = [{xmlcdata, <<>>}]}]; + attrs = #{<<"xmlns">> => ?NS_DELAY, + <<"from">> => jid:to_binary(ModifUSR), + <<"stamp">> => list_to_binary(TString)}, + children = [#xmlcdata{content = <<>>}]}]; _ -> [] end, + Attrs = node_attr(Node), event_stanza_with_els([#xmlel{name = <<"items">>, - attrs = [{<<"type">>, <<"headline">>} | node_attr(Node)], + attrs = Attrs#{<<"type">> => <<"headline">>}, children = items_els(Items)}], MoreEls). event_stanza(Els) -> event_stanza_with_els(Els, []). event_stanza_with_els(Els, MoreEls) -> - #xmlel{name = <<"message">>, attrs = [], + #xmlel{name = <<"message">>, children = [#xmlel{name = <<"event">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB_EVENT}], + attrs = #{<<"xmlns">> => ?NS_PUBSUB_EVENT}, children = Els} | MoreEls]}. @@ -3670,7 +3673,7 @@ get_configure_transaction(ServerHost, Node, From, Lang, children = [XEl]}, {result, [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB_OWNER}], + attrs = #{<<"xmlns">> => ?NS_PUBSUB_OWNER}, children = [ConfigureEl]}]}; _ -> {error, mongoose_xmpp_errors:forbidden()} @@ -3680,10 +3683,10 @@ get_default(Host, Node, _From, #{lang := Lang}) -> Type = select_type(Host, Node), Options = node_options(Host, Type), XEl = configure_form(<<"form">>, Options, Lang, []), - DefaultEl = #xmlel{name = <<"default">>, attrs = [], children = [XEl]}, + DefaultEl = #xmlel{name = <<"default">>, children = [XEl]}, {result, [#xmlel{name = <<"pubsub">>, - attrs = [{<<"xmlns">>, ?NS_PUBSUB_OWNER}], + attrs = #{<<"xmlns">> => ?NS_PUBSUB_OWNER}, children = [DefaultEl]}]}. match_option(Node, Var, Val) when is_record(Node, pubsub_node) -> @@ -4290,17 +4293,16 @@ db_call_fun(Host, Node, Action) -> %%%% helpers %% Add pubsub-specific error element -extended_error(Error, Ext) -> - extended_error(Error, Ext, [{<<"xmlns">>, ?NS_PUBSUB_ERRORS}]). +extended_error(#xmlel{} = Error, Ext) when is_binary(Ext) -> + extend_error(Error, Ext, #{<<"xmlns">> => ?NS_PUBSUB_ERRORS}). -extended_error(Error, unsupported, Feature) -> +unsupported_error(Error, Feature) -> %% Give a uniq identifier - extended_error(Error, <<"unsupported">>, - [{<<"xmlns">>, ?NS_PUBSUB_ERRORS}, - {<<"feature">>, Feature}]); -extended_error(#xmlel{name = Error, attrs = Attrs, children = SubEls}, Ext, ExtAttrs) -> - #xmlel{name = Error, attrs = Attrs, - children = lists:reverse([#xmlel{name = Ext, attrs = ExtAttrs} | SubEls])}. + extend_error(Error, <<"unsupported">>, + #{<<"xmlns">> => ?NS_PUBSUB_ERRORS, <<"feature">> => Feature}). + +extend_error(#xmlel{children = SubEls} = El, Ext, ExtAttrs) -> + El#xmlel{children = lists:reverse([#xmlel{name = Ext, attrs = ExtAttrs} | SubEls])}. string_to_ljid(JID) -> case jid:from_binary(JID) of @@ -4317,17 +4319,15 @@ string_to_ljid(JID) -> uniqid() -> uuid:uuid_to_string(uuid:get_v4(), binary_standard). -node_attr(Node) -> [{<<"node">>, Node}]. +node_attr(Node) -> #{<<"node">> => Node}. -item_attr([]) -> []; -item_attr(ItemId) -> [{<<"id">>, ItemId}]. +item_attr([]) -> #{}; +item_attr(ItemId) -> #{<<"id">> => ItemId}. item_attr(ItemId, undefined) -> item_attr(ItemId); -item_attr([], Publisher) -> [{<<"publisher">>, - jid:to_binary(jid:to_lower(Publisher))}]; -item_attr(ItemId, Publisher) -> [{<<"id">>, ItemId}, - {<<"publisher">>, - jid:to_binary(jid:to_lower(Publisher))}]. +item_attr([], Publisher) -> #{<<"publisher">> => jid:to_binary(jid:to_lower(Publisher))}; +item_attr(ItemId, Publisher) -> #{<<"id">> => ItemId, + <<"publisher">> => jid:to_binary(jid:to_lower(Publisher))}. items_els(Items) -> [#xmlel{name = <<"item">>, attrs = item_attr(ItemId, Publisher), children = Payload} @@ -4337,7 +4337,7 @@ items_els(Items) -> add_message_type(Message, normal) -> Message; add_message_type(#xmlel{name = <<"message">>, attrs = Attrs, children = Els}, Type) -> #xmlel{name = <<"message">>, - attrs = [{<<"type">>, atom_to_binary(Type, utf8)} | Attrs], + attrs = Attrs#{<<"type">> => atom_to_binary(Type, utf8)}, children = Els}; add_message_type(XmlEl, _Type) -> XmlEl. @@ -4364,27 +4364,27 @@ add_extended_headers(Stanza, HeaderEls) -> add_headers(#xmlel{name = Name, attrs = Attrs, children = Els}, HeaderName, HeaderNS, HeaderEls) -> HeaderEl = #xmlel{name = HeaderName, - attrs = [{<<"xmlns">>, HeaderNS}], + attrs = #{<<"xmlns">> => HeaderNS}, children = HeaderEls}, #xmlel{name = Name, attrs = Attrs, children = lists:append(Els, [HeaderEl])}. subid_shim(SubIds) -> [#xmlel{ name = <<"header">>, - attrs = [{<<"name">>, <<"SubId">>}], + attrs = #{<<"name">> => <<"SubId">>}, children = [#xmlcdata{ content = SubId }]} || SubId <- SubIds]. collection_shim(CollectionNode) -> #xmlel{ name = <<"header">>, - attrs = [{<<"name">>, <<"Collection">>}], + attrs = #{<<"name">> => <<"Collection">>}, children = [#xmlcdata{ content = CollectionNode }] }. %% The argument is a list of Jids because this function could be used %% with the 'pubsub#replyto' (type=jid-multi) node configuration. extended_headers(Jids) -> [#xmlel{name = <<"address">>, - attrs = [{<<"type">>, <<"replyto">>}, {<<"jid">>, Jid}]} + attrs = #{<<"type">> => <<"replyto">>, <<"jid">> => Jid}} || Jid <- Jids]. -spec on_user_offline(Acc, Params, Extra) -> {ok, Acc} when diff --git a/src/roster/mod_roster.erl b/src/roster/mod_roster.erl index cf862ebead7..e3a6451fbfb 100644 --- a/src/roster/mod_roster.erl +++ b/src/roster/mod_roster.erl @@ -225,7 +225,7 @@ get_versioning_feature(Acc, _, #{host_type := HostType}) -> NewAcc = case roster_versioning_enabled(HostType) of true -> Feature = #xmlel{name = <<"ver">>, - attrs = [{<<"xmlns">>, ?NS_ROSTER_VER}]}, + attrs = #{<<"xmlns">> => ?NS_ROSTER_VER}}, [Feature | Acc]; false -> [] end, @@ -313,12 +313,12 @@ create_sub_el(false, false) -> []; create_sub_el(Items, false) -> [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_ROSTER}], + attrs = #{<<"xmlns">> => ?NS_ROSTER}, children = Items}]; create_sub_el(Items, Version) -> [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_ROSTER}, - {<<"ver">>, Version}], + attrs = #{<<"xmlns">> => ?NS_ROSTER, + <<"ver">> => Version}, children = Items}]. -spec get_user_roster(Acc, Params, Extra) -> {ok, Acc} when @@ -344,23 +344,23 @@ do_get_user_roster(HostType, #jid{luser = LUser, lserver = LServer}) -> -spec item_to_xml(roster()) -> exml:element(). item_to_xml(Item) -> - Attrs0 = [{<<"jid">>, jid:to_binary(Item#roster.jid)}, - {<<"subscription">>, subs_to_binary(Item#roster.subscription)}], + Attrs0 = #{<<"jid">> => jid:to_binary(Item#roster.jid), + <<"subscription">> => subs_to_binary(Item#roster.subscription)}, Attrs1 = maybe_append_ask(Attrs0, Item), Attrs2 = maybe_append_name(Attrs1, Item), Fold = fun(G, Acc) -> [group_el(G) | Acc] end, SubEls = lists:foldl(Fold, Item#roster.xs, Item#roster.groups), #xmlel{name = <<"item">>, attrs = Attrs2, children = SubEls}. --spec maybe_append_name([exml:attr()], roster()) -> [exml:attr()]. +-spec maybe_append_name(exml:attrs(), roster()) -> exml:attrs(). maybe_append_name(Attrs, #roster{name = <<>>}) -> Attrs; maybe_append_name(Attrs, #roster{name = Name}) -> - [{<<"name">>, Name} | Attrs]. + Attrs#{<<"name">> => Name}. --spec maybe_append_ask([exml:attr()], roster()) -> [exml:attr()]. +-spec maybe_append_ask(exml:attrs(), roster()) -> exml:attrs(). maybe_append_ask(Attrs, #roster{ask = Ask}) when Ask =:= subscribe; Ask =:= out; Ask =:= both -> - [{<<"ask">>, <<"subscribe">>} | Attrs]; + Attrs#{<<"ask">> => <<"subscribe">>}; maybe_append_ask(Attrs, _) -> Attrs. @@ -453,22 +453,26 @@ new_roster_item(UserJid, ContactLJID) -> us = jid:to_lus(UserJid), jid = ContactLJID}. -process_item_attrs(Item, [{<<"jid">>, Val} | Attrs]) -> +process_item_attrs(Item0, Attrs) -> + Item1 = maybe_add_jid(Item0, Attrs), + Item2 = maybe_add_name(Item1, Attrs), + maybe_add_subs(Item2, Attrs, true). + +maybe_add_jid(Item, #{<<"jid">> := Val}) -> case jid:from_binary(Val) of error -> - process_item_attrs(Item, Attrs); + Item; JID1 -> JID = jid:to_lower(JID1), - process_item_attrs(Item#roster{jid = JID}, Attrs) + Item#roster{jid = JID} end; -process_item_attrs(Item, [{<<"name">>, Val} | Attrs]) -> - process_item_attrs(Item#roster{name = Val}, Attrs); -process_item_attrs(Item, [{<<"subscription">>, <<"remove">>} | Attrs]) -> - process_item_attrs(Item#roster{subscription = remove}, Attrs); -process_item_attrs(Item, [_ | Attrs]) -> - process_item_attrs(Item, Attrs); -process_item_attrs(Item, []) -> - Item. +maybe_add_jid(Item, _) -> + Item. + +maybe_add_name(Item, #{<<"name">> := Val}) -> + Item#roster{name = Val}; +maybe_add_name(Item, _) -> + Item. process_item_els(Item, [#xmlel{name = Name} = El | Els]) -> case Name of @@ -520,8 +524,8 @@ push_item_version(JID, From, Item, RosterVersion) -> push_item_final(JID, From, Item, RosterVersion) -> ExtraAttrs = case RosterVersion of - not_found -> []; - _ -> [{<<"ver">>, RosterVersion}] + not_found -> #{}; + _ -> #{<<"ver">> => RosterVersion} end, ResIQ = #iq{type = set, xmlns = ?NS_ROSTER, %% @doc Roster push, calculate and include the version attribute. @@ -529,7 +533,7 @@ push_item_final(JID, From, Item, RosterVersion) -> id = <<"push", (mongoose_bin:gen_from_crypto())/binary>>, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_ROSTER} | ExtraAttrs], + attrs = ExtraAttrs#{<<"xmlns">> => ?NS_ROSTER}, children = [item_to_xml(Item)]}]}, ejabberd_router:route(From, JID, jlib:iq_to_xml(ResIQ)). @@ -566,9 +570,9 @@ build_pending(#roster{ask = Ask} = I, JID, P) children = [#xmlcdata{content = Status}]}, El = #xmlel{ name = <<"presence">>, - attrs = [{<<"from">>, jid:to_binary(I#roster.jid)}, - {<<"to">>, jid:to_binary(JID)}, - {<<"type">>, <<"subscribe">>}], + attrs = #{<<"from">> => jid:to_binary(I#roster.jid), + <<"to">> => jid:to_binary(JID), + <<"type">> => <<"subscribe">>}, children = [StatusEl]}, [El | P]; build_pending(_, _, P) -> @@ -620,7 +624,7 @@ process_subscription(HostType, Direction, JID, ContactJID, Type, Reason) -> none -> ok; _ -> PresenceStanza = #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, autoreply_to_type(AutoReply)}], + attrs = #{<<"type">> => autoreply_to_type(AutoReply)}, children = []}, ejabberd_router:route(JID, ContactJID, PresenceStanza) end, @@ -850,7 +854,7 @@ send_unsubscribing_presence(From, #roster{ subscription = Subscription } = Item) send_presence_type(From, To, Type) -> ejabberd_router:route(From, To, #xmlel{name = <<"presence">>, - attrs = [{<<"type">>, Type}], children = []}). + attrs = #{<<"type">> => Type}, children = []}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -920,30 +924,23 @@ process_item_set_t(HostType, JID, end; process_item_set_t(_HostType, _Jid, _) -> ok. -process_item_attrs_ws(Item, [{<<"jid">>, Val} | Attrs]) -> - case jid:from_binary(Val) of - error -> - process_item_attrs_ws(Item, Attrs); - JID1 -> - JID = {JID1#jid.luser, JID1#jid.lserver, JID1#jid.lresource}, - process_item_attrs_ws(Item#roster{jid = JID}, Attrs) - end; -process_item_attrs_ws(Item, [{<<"name">>, Val} | Attrs]) -> - process_item_attrs_ws(Item#roster{name = Val}, Attrs); -process_item_attrs_ws(Item, [{<<"subscription">>, <<"remove">>} | Attrs]) -> - process_item_attrs_ws(Item#roster{subscription = remove}, Attrs); -process_item_attrs_ws(Item, [{<<"subscription">>, <<"none">>} | Attrs]) -> - process_item_attrs_ws(Item#roster{subscription = none}, Attrs); -process_item_attrs_ws(Item, [{<<"subscription">>, <<"both">>} | Attrs]) -> - process_item_attrs_ws(Item#roster{subscription = both}, Attrs); -process_item_attrs_ws(Item, [{<<"subscription">>, <<"from">>} | Attrs]) -> - process_item_attrs_ws(Item#roster{subscription = from}, Attrs); -process_item_attrs_ws(Item, [{<<"subscription">>, <<"to">>} | Attrs]) -> - process_item_attrs_ws(Item#roster{subscription = to}, Attrs); -process_item_attrs_ws(Item, [_ | Attrs]) -> - process_item_attrs_ws(Item, Attrs); -process_item_attrs_ws(Item, []) -> - Item. +process_item_attrs_ws(Item0, Attrs) -> + Item1 = maybe_add_jid(Item0, Attrs), + Item2 = maybe_add_name(Item1, Attrs), + maybe_add_subs(Item2, Attrs, false). + +maybe_add_subs(Item, #{<<"subscription">> := <<"remove">>}, _OnlyRemoveSubs) -> + Item#roster{subscription = remove}; +maybe_add_subs(Item, #{<<"subscription">> := <<"none">>}, false) -> + Item#roster{subscription = none}; +maybe_add_subs(Item, #{<<"subscription">> := <<"both">>}, false) -> + Item#roster{subscription = both}; +maybe_add_subs(Item, #{<<"subscription">> := <<"from">>}, false) -> + Item#roster{subscription = from}; +maybe_add_subs(Item, #{<<"subscription">> := <<"to">>}, false) -> + Item#roster{subscription = to}; +maybe_add_subs(Item, _, _) -> + Item. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/roster/mod_roster_api.erl b/src/roster/mod_roster_api.erl index c9c50966d85..c3a7a24fb66 100644 --- a/src/roster/mod_roster_api.erl +++ b/src/roster/mod_roster_api.erl @@ -105,7 +105,7 @@ delete_contact(#jid{lserver = LServer} = CallerJID, ContactJID) -> {ok | unknown_domain, iolist()}. subscription(#jid{lserver = LServer} = CallerJID, ContactJID, Type) -> StanzaType = atom_to_binary(Type, latin1), - El = #xmlel{name = <<"presence">>, attrs = [{<<"type">>, StanzaType}]}, + El = #xmlel{name = <<"presence">>, attrs = #{<<"type">> => StanzaType}}, case mongoose_domain_api:get_domain_host_type(LServer) of {ok, HostType} -> Acc1 = mongoose_acc:new(#{ location => ?LOCATION, diff --git a/src/s2s/mongoose_s2s_dialback.erl b/src/s2s/mongoose_s2s_dialback.erl index b3e49f5ecd4..f49db0488fc 100644 --- a/src/s2s/mongoose_s2s_dialback.erl +++ b/src/s2s/mongoose_s2s_dialback.erl @@ -63,28 +63,29 @@ step_1(FromTo, Key) -> %% Receiving server sends verification request to authoritative server (step 2) -spec step_2(ejabberd_s2s:fromto(), ejabberd_s2s:s2s_dialback_key(), ejabberd_s2s:stream_id()) -> exml:element(). step_2(FromTo, Key, StreamID) -> + Attrs = fromto_to_attrs(FromTo), #xmlel{name = <<"db:verify">>, - attrs = [{<<"id">>, StreamID} | fromto_to_attrs(FromTo)], + attrs = Attrs#{<<"id">> => StreamID}, children = [#xmlcdata{content = Key}]}. %% Receiving server is informed by authoritative server that key is valid or invalid (step 3) -spec step_3(ejabberd_s2s:fromto(), ejabberd_s2s:stream_id(), boolean()) -> exml:element(). step_3(FromTo, StreamID, IsValid) -> + Attrs = fromto_to_attrs(FromTo), #xmlel{name = <<"db:verify">>, - attrs = [{<<"id">>, StreamID}, - {<<"type">>, is_valid_to_type(IsValid)} - | fromto_to_attrs(FromTo)]}. + attrs = Attrs#{<<"id">> => StreamID, + <<"type">> => is_valid_to_type(IsValid)}}. %% Receiving server sends valid or invalid verification result to initiating server (step 4) -spec step_4(ejabberd_s2s:fromto(), boolean()) -> exml:element(). step_4(FromTo, IsValid) -> + Attrs = fromto_to_attrs(FromTo), #xmlel{name = <<"db:result">>, - attrs = [{<<"type">>, is_valid_to_type(IsValid)} - | fromto_to_attrs(FromTo)]}. + attrs = Attrs#{<<"type">> => is_valid_to_type(IsValid)}}. --spec fromto_to_attrs(ejabberd_s2s:fromto()) -> [{binary(), binary()}]. +-spec fromto_to_attrs(ejabberd_s2s:fromto()) -> exml:attrs(). fromto_to_attrs({LocalServer, RemoteServer}) -> - [{<<"from">>, LocalServer}, {<<"to">>, RemoteServer}]. + #{<<"from">> => LocalServer, <<"to">> => RemoteServer}. is_valid_to_type(true) -> <<"valid">>; is_valid_to_type(false) -> <<"invalid">>. diff --git a/src/smart_markers/mod_smart_markers.erl b/src/smart_markers/mod_smart_markers.erl index 0e3040fd874..c2cc8f0ec89 100644 --- a/src/smart_markers/mod_smart_markers.erl +++ b/src/smart_markers/mod_smart_markers.erl @@ -136,10 +136,10 @@ async_config_spec() -> process_iq(Acc, _From, _To, #iq{type = set, sub_el = SubEl} = IQ, _Extra) -> {Acc, IQ#iq{type = error, sub_el = [SubEl, mongoose_xmpp_errors:not_allowed()]}}; process_iq(Acc, From, _To, #iq{type = get, sub_el = SubEl} = IQ, #{keep_private := Private}) -> - Req = maps:from_list(SubEl#xmlel.attrs), - MaybePeer = jid:from_binary(maps:get(<<"peer">>, Req, undefined)), - MaybeAfter = parse_ts(maps:get(<<"after">>, Req, undefined)), - MaybeThread = maps:get(<<"thread">>, Req, undefined), + Attrs = SubEl#xmlel.attrs, + MaybePeer = jid:from_binary(maps:get(<<"peer">>, Attrs, undefined)), + MaybeAfter = parse_ts(maps:get(<<"after">>, Attrs, undefined)), + MaybeThread = maps:get(<<"thread">>, Attrs, undefined), Res = fetch_markers(IQ, Acc, From, MaybePeer, MaybeThread, MaybeAfter, Private), {Acc, Res}. @@ -168,27 +168,29 @@ fetch_markers(IQ, Acc, From, Peer, Thread, TS, Private) -> HostType = mongoose_acc:host_type(Acc), Markers = mod_smart_markers_backend:get_conv_chat_marker(HostType, From, Peer, Thread, TS, Private), SubEl = #xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_ESL_SMART_MARKERS}, - {<<"peer">>, jid:to_bare_binary(Peer)}], + attrs = #{<<"xmlns">> => ?NS_ESL_SMART_MARKERS, + <<"peer">> => jid:to_bare_binary(Peer)}, children = build_result(Markers)}, IQ#iq{type = result, sub_el = SubEl}. build_result(Markers) -> - [ #xmlel{name = <<"marker">>, - attrs = [{<<"id">>, MsgId}, - {<<"from">>, jid:to_binary(From)}, - {<<"type">>, atom_to_binary(Type)}, - {<<"timestamp">>, ts_to_bin(MsgTS)} - | maybe_thread(MsgThread) ]} + [ begin + Attrs = maybe_thread(MsgThread), + #xmlel{name = <<"marker">>, + attrs = Attrs#{<<"id">> => MsgId, + <<"from">> => jid:to_binary(From), + <<"type">> => atom_to_binary(Type), + <<"timestamp">> => ts_to_bin(MsgTS)}} + end || #{from := From, thread := MsgThread, type := Type, timestamp := MsgTS, id := MsgId} <- Markers ]. ts_to_bin(TS) -> list_to_binary(calendar:system_time_to_rfc3339(TS, [{offset, "Z"}, {unit, microsecond}])). maybe_thread(undefined) -> - []; + #{}; maybe_thread(Bin) -> - [{<<"thread">>, Bin}]. + #{<<"thread">> => Bin}. %% HOOKS -spec hooks(mongooseim:host_type(), gen_mod:module_opts()) -> gen_hook:hook_list(). diff --git a/src/stream_management/mod_stream_management.erl b/src/stream_management/mod_stream_management.erl index c92e19f1ef6..f69354c9946 100644 --- a/src/stream_management/mod_stream_management.erl +++ b/src/stream_management/mod_stream_management.erl @@ -523,7 +523,7 @@ register_smid_return_enabled_stanza(StateData) -> Sid = mongoose_c2s:get_sid(StateData), HostType = mongoose_c2s:get_host_type(StateData), ok = register_smid(HostType, SMID, Sid), - mod_stream_management_stanzas:stream_mgmt_enabled([{<<"id">>, SMID}, {<<"resume">>, <<"true">>}]). + mod_stream_management_stanzas:stream_mgmt_enabled(#{<<"id">> => SMID, <<"resume">> => <<"true">>}). -spec if_not_already_enabled_create_sm_state(mongoose_c2s:data()) -> sm_state() | error. if_not_already_enabled_create_sm_state(StateData) -> @@ -591,7 +591,9 @@ do_handle_resume(StateData, _C2SState, SMID, H, {sid, {_TS, Pid}}) -> do_handle_resume(StateData, _C2SState, SMID, _H, {stale_h, StaleH}) -> ?LOG_WARNING(#{what => resumption_error, reason => session_resumption_timed_out, smid => SMID, stale_h => StaleH, c2s_state => StateData}), - {stream_mgmt_error, mod_stream_management_stanzas:stream_mgmt_failed(<<"item-not-found">>, [{<<"h">>, integer_to_binary(StaleH)}])}; + {stream_mgmt_error, + mod_stream_management_stanzas:stream_mgmt_failed(<<"item-not-found">>, + #{<<"h">> => integer_to_binary(StaleH)})}; do_handle_resume(StateData, _C2SState, SMID, _H, {error, smid_not_found}) -> ?LOG_WARNING(#{what => resumption_error, reason => no_previous_session_for_smid, smid => SMID, c2s_state => StateData}), diff --git a/src/stream_management/mod_stream_management_sasl2.erl b/src/stream_management/mod_stream_management_sasl2.erl index 19bfdb7a02b..b666aedadcc 100644 --- a/src/stream_management/mod_stream_management_sasl2.erl +++ b/src/stream_management/mod_stream_management_sasl2.erl @@ -28,7 +28,7 @@ hooks(HostType) -> -spec sasl2_stream_features(Acc, #{c2s_data := mongoose_c2s:data()}, gen_hook:extra()) -> {ok, Acc} when Acc :: [exml:element()]. sasl2_stream_features(Acc, _, _) -> - Resume = #xmlel{name = <<"sm">>, attrs = [{<<"xmlns">>, ?NS_STREAM_MGNT_3}]}, + Resume = #xmlel{name = <<"sm">>, attrs = #{<<"xmlns">> => ?NS_STREAM_MGNT_3}}, {ok, [Resume | Acc]}. -spec sasl2_start(SaslAcc, #{stanza := exml:element()}, gen_hook:extra()) -> @@ -55,7 +55,7 @@ sasl2_success(SaslAcc, _, _) -> -spec bind2_stream_features(Acc, #{c2s_data := mongoose_c2s:data()}, gen_hook:extra()) -> {ok, Acc} when Acc :: [exml:element()]. bind2_stream_features(Acc, _, _) -> - SmFeature = #xmlel{name = <<"feature">>, attrs = [{<<"var">>, ?NS_STREAM_MGNT_3}]}, + SmFeature = #xmlel{name = <<"feature">>, attrs = #{<<"var">> => ?NS_STREAM_MGNT_3}}, {ok, [SmFeature | Acc]}. -spec bind2_enable_features(SaslAcc, mod_sasl2:c2s_state_data(), gen_hook:extra()) -> diff --git a/src/stream_management/mod_stream_management_stanzas.erl b/src/stream_management/mod_stream_management_stanzas.erl index aac422e140c..945e026932c 100644 --- a/src/stream_management/mod_stream_management_stanzas.erl +++ b/src/stream_management/mod_stream_management_stanzas.erl @@ -18,51 +18,51 @@ -spec sm() -> exml:element(). sm() -> #xmlel{name = <<"sm">>, - attrs = [{<<"xmlns">>, ?NS_STREAM_MGNT_3}]}. + attrs = #{<<"xmlns">> => ?NS_STREAM_MGNT_3}}. -spec stream_mgmt_enabled() -> exml:element(). stream_mgmt_enabled() -> - stream_mgmt_enabled([]). + stream_mgmt_enabled(#{}). --spec stream_mgmt_enabled([exml:attr()]) -> exml:element(). +-spec stream_mgmt_enabled(exml:attrs()) -> exml:element(). stream_mgmt_enabled(ExtraAttrs) -> #xmlel{name = <<"enabled">>, - attrs = [{<<"xmlns">>, ?NS_STREAM_MGNT_3}] ++ ExtraAttrs}. + attrs = ExtraAttrs#{<<"xmlns">> => ?NS_STREAM_MGNT_3}}. -spec stream_mgmt_resumed(mod_stream_management:smid(), mod_stream_management:short()) -> exml:element(). stream_mgmt_resumed(SMID, Handled) -> #xmlel{name = <<"resumed">>, - attrs = [{<<"xmlns">>, ?NS_STREAM_MGNT_3}, - {<<"previd">>, SMID}, - {<<"h">>, integer_to_binary(Handled)}]}. + attrs = #{<<"xmlns">> => ?NS_STREAM_MGNT_3, + <<"previd">> => SMID, + <<"h">> => integer_to_binary(Handled)}}. -spec stream_mgmt_failed(binary()) -> exml:element(). stream_mgmt_failed(Reason) -> - stream_mgmt_failed(Reason, []). + stream_mgmt_failed(Reason, #{}). --spec stream_mgmt_failed(binary(), [exml:attr()]) -> exml:element(). +-spec stream_mgmt_failed(binary(), exml:attrs()) -> exml:element(). stream_mgmt_failed(Reason, Attrs) -> ReasonEl = #xmlel{name = Reason, - attrs = [{<<"xmlns">>, ?NS_STANZAS}]}, + attrs = #{<<"xmlns">> => ?NS_STANZAS}}, #xmlel{name = <<"failed">>, - attrs = [{<<"xmlns">>, ?NS_STREAM_MGNT_3} | Attrs], + attrs = Attrs#{<<"xmlns">> => ?NS_STREAM_MGNT_3}, children = [ReasonEl]}. -spec stream_mgmt_ack(non_neg_integer()) -> exml:element(). stream_mgmt_ack(NIncoming) -> #xmlel{name = <<"a">>, - attrs = [{<<"xmlns">>, ?NS_STREAM_MGNT_3}, - {<<"h">>, integer_to_binary(NIncoming)}]}. + attrs = #{<<"xmlns">> => ?NS_STREAM_MGNT_3, + <<"h">> => integer_to_binary(NIncoming)}}. -spec stream_mgmt_request() -> exml:element(). stream_mgmt_request() -> #xmlel{name = <<"r">>, - attrs = [{<<"xmlns">>, ?NS_STREAM_MGNT_3}]}. + attrs = #{<<"xmlns">> => ?NS_STREAM_MGNT_3}}. -spec sm_handled_count_too_high_stanza(non_neg_integer(), non_neg_integer()) -> exml:element(). sm_handled_count_too_high_stanza(Handled, OldAcked) -> #xmlel{name = <<"handled-count-too-high">>, - attrs = [{<<"xmlns">>, ?NS_STREAM_MGNT_3}, - {<<"h">>, integer_to_binary(Handled)}, - {<<"send-count">>, integer_to_binary(OldAcked)}]}. + attrs = #{<<"xmlns">> => ?NS_STREAM_MGNT_3, + <<"h">> => integer_to_binary(Handled), + <<"send-count">> => integer_to_binary(OldAcked)}}. diff --git a/src/tr_util.erl b/src/tr_util.erl index 156afc00fb2..f9d412be1d8 100644 --- a/src/tr_util.erl +++ b/src/tr_util.erl @@ -151,8 +151,8 @@ element_info(Data, Hook, #{element := Element, ref := Ref, from_jid := From, to_ to_jid => jid:to_binary(To)}, maps:merge(Info, element_attr_info(Element#xmlel.attrs)). --spec element_attr_info([exml:attr()]) -> #{atom() => binary()}. +-spec element_attr_info(exml:attrs()) -> #{atom() => binary()}. element_attr_info(Attrs) -> AllowedAttrs = [<<"id">>, <<"type">>], - maps:from_list([{binary_to_existing_atom(Key), Value} || {Key, Value} <- Attrs, - lists:member(Key, AllowedAttrs)]). + #{binary_to_existing_atom(Key) => Value || + Key := Value <- maps:with(AllowedAttrs, Attrs)}. diff --git a/src/vcard/mod_vcard.erl b/src/vcard/mod_vcard.erl index 3c6b9bb9b2d..eed0a780225 100644 --- a/src/vcard/mod_vcard.erl +++ b/src/vcard/mod_vcard.erl @@ -354,7 +354,7 @@ process_local_iq(Acc, _From, _To, IQ = #iq{type = get}, _Extra) -> DescCData = #xmlcdata{content = [<<"MongooseIM XMPP Server">>, <<"\nCopyright (c) Erlang Solutions Ltd.">>]}, {Acc, IQ#iq{type = result, - sub_el = [#xmlel{name = <<"vCard">>, attrs = [{<<"xmlns">>, ?NS_VCARD}], + sub_el = [#xmlel{name = <<"vCard">>, attrs = #{<<"xmlns">> => ?NS_VCARD}, children = [#xmlel{name = <<"FN">>, children = [#xmlcdata{content = <<"MongooseIM">>}]}, #xmlel{name = <<"URL">>, @@ -501,7 +501,7 @@ do_route(HostType, _LServer, From, To, Acc, InfoXML = mongoose_disco:get_info(HostType, ?MODULE, <<>>, <<>>), ResIQ = IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_DISCO_INFO}], + attrs = #{<<"xmlns">> => ?NS_DISCO_INFO}, children = IdentityXML ++ FeatureXML ++ InfoXML}]}, ejabberd_router:route(To, From, Acc, jlib:iq_to_xml(ResIQ)); do_route(_HostType, _LServer, From, To, Acc, @@ -513,14 +513,14 @@ do_route(_HostType, _LServer, From, To, Acc, ResIQ = IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_DISCO_ITEMS}]}]}, + attrs = #{<<"xmlns">> => ?NS_DISCO_ITEMS}}]}, ejabberd_router:route(To, From, Acc, jlib:iq_to_xml(ResIQ)); do_route(_HostType, _LServer, From, To, Acc, #iq{type = get, xmlns = ?NS_VCARD} = IQ) -> ResIQ = IQ#iq{type = result, sub_el = [#xmlel{name = <<"vCard">>, - attrs = [{<<"xmlns">>, ?NS_VCARD}], + attrs = #{<<"xmlns">> => ?NS_VCARD}, children = iq_get_vcard()}]}, ejabberd_router:route(To, From, Acc, jlib:iq_to_xml(ResIQ)); do_route(_HostType, _LServer, From, To, Acc, _IQ) -> @@ -530,13 +530,13 @@ do_route(_HostType, _LServer, From, To, Acc, _IQ) -> make_search_form_result_iq(IQ, Elements) -> IQ#iq{type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_SEARCH}], + attrs = #{<<"xmlns">> => ?NS_SEARCH}, children = Elements }]}. search_instructions(Lang) -> Text = translate:translate(Lang, <<"You need an x:data capable client to search">>), - #xmlel{name = <<"instructions">>, attrs = [], children = [#xmlcdata{content = Text}]}. + #xmlel{name = <<"instructions">>, children = [#xmlcdata{content = Text}]}. search_form(JID, SearchFields, Lang) -> Title = <<(translate:translate(Lang, <<"Search users in ">>))/binary, @@ -569,7 +569,7 @@ make_search_result_iq(IQ, SearchResult, RSMOutEls) -> IQ#iq{ type = result, sub_el = [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_SEARCH}], + attrs = #{<<"xmlns">> => ?NS_SEARCH}, children = [Form | RSMOutEls]} ]}. diff --git a/src/vcard/mod_vcard_api.erl b/src/vcard/mod_vcard_api.erl index 8da35d21d05..6f7c3305295 100644 --- a/src/vcard/mod_vcard_api.erl +++ b/src/vcard/mod_vcard_api.erl @@ -73,14 +73,13 @@ check_user(JID = #jid{lserver = LServer}) -> transform_from_map(Vcard) -> #xmlel{name = <<"vCard">>, - attrs = [{<<"xmlns">>, <<"vcard-temp">>}], + attrs = #{<<"xmlns">> => <<"vcard-temp">>}, children = lists:foldl(fun({Name, Value}, Acc) -> Acc ++ transform_field_and_value(Name, Value) end, [], maps:to_list(Vcard))}. construct_xmlel(Name, Children) when is_list(Children)-> [#xmlel{name = Name, - attrs = [], children = Children}]. transform_field_and_value(_Name, null) -> @@ -92,7 +91,7 @@ transform_field_and_value(Name, Value) when is_list(Value) -> transform_field_and_value(Name, Value) when is_map(Value) -> construct_xmlel(from_map_to_xml(Name), process_child_map(Value)); transform_field_and_value(Name, Value) -> - construct_xmlel(from_map_to_xml(Name), [{xmlcdata, Value}]). + construct_xmlel(from_map_to_xml(Name), [#xmlcdata{content = Value}]). transform_subfield_and_value(_Name, null) -> []; @@ -104,10 +103,10 @@ transform_subfield_and_value(<<"tags">>, TagsList) -> end, [], TagsList); transform_subfield_and_value(Name, Value) when is_list(Value) -> lists:foldl(fun(Element, Acc) -> - Acc ++ construct_xmlel(from_map_to_xml(Name), [{xmlcdata, Element}]) + Acc ++ construct_xmlel(from_map_to_xml(Name), [#xmlcdata{content = Element}]) end, [], Value); transform_subfield_and_value(Name, Value) -> - construct_xmlel(from_map_to_xml(Name), [{xmlcdata, Value}]). + construct_xmlel(from_map_to_xml(Name), [#xmlcdata{content = Value}]). process_child_map(Value) -> lists:foldl(fun({Name, SubfieldValue}, Acc) -> @@ -134,7 +133,7 @@ to_map_format(Vcard) -> maps:merge(Acc, transform_from_xml(Name, Value, Acc)) end, #{}, Vcard). -transform_from_xml(<<"FN">>, [{_, Value}], _) -> +transform_from_xml(<<"FN">>, [#xmlcdata{content = Value}], _) -> #{<<"formattedName">> => Value}; transform_from_xml(<<"N">>, Value, _) -> #{<<"nameComponents">> => lists:foldl(fun name_components_process/2, #{}, Value)}; @@ -195,12 +194,12 @@ transform_from_xml(<<"KEY">>, Value, Acc) -> transform_from_xml(_, _, _) -> #{}. -process_value([{_, Value}]) -> +process_value([#xmlcdata{content = Value}]) -> Value; process_value(_) -> null. -simple_process(Name, [{_, Value}], Acc) -> +simple_process(Name, [#xmlcdata{content = Value}], Acc) -> List = maps:get(Name, Acc, []), #{Name => List ++ [{ok, Value}]}; simple_process(_, _, _) -> diff --git a/src/vcard/mod_vcard_ldap.erl b/src/vcard/mod_vcard_ldap.erl index 1cbb8ef492f..d24c4179b7a 100644 --- a/src/vcard/mod_vcard_ldap.erl +++ b/src/vcard/mod_vcard_ldap.erl @@ -234,98 +234,97 @@ ldap_attributes_to_vcard(Attributes, VCardMap, UD) -> AElts = [ldap_attribute_to_vcard(vCardA, Attr) || Attr <- Attrs], [#xmlel{name = <<"vCard">>, - attrs = [{<<"xmlns">>, ?NS_VCARD}], + attrs = #{<<"xmlns">> => ?NS_VCARD}, children = lists:append([X || X <- Elts, X /= none], - [#xmlel{name = <<"N">>, attrs = [], + [#xmlel{name = <<"N">>, children = [X || X <- NElts, X /= none]}, - #xmlel{name = <<"ORG">>, attrs = [], + #xmlel{name = <<"ORG">>, children = [X || X <- OElts, X /= none]}, - #xmlel{name = <<"ADR">>, attrs = [], + #xmlel{name = <<"ADR">>, children = [X || X <- AElts, X /= none]}])}]. ldap_attribute_to_vcard(vCard, {<<"fn">>, Value}) -> - #xmlel{name = <<"FN">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"FN">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCard, {<<"nickname">>, Value}) -> - #xmlel{name = <<"NICKNAME">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"NICKNAME">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCard, {<<"title">>, Value}) -> - #xmlel{name = <<"TITLE">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"TITLE">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCard, {<<"bday">>, Value}) -> - #xmlel{name = <<"BDAY">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"BDAY">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCard, {<<"url">>, Value}) -> - #xmlel{name = <<"URL">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"URL">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCard, {<<"desc">>, Value}) -> - #xmlel{name = <<"DESC">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"DESC">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCard, {<<"role">>, Value}) -> - #xmlel{name = <<"ROLE">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"ROLE">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCard, {<<"tel">>, Value}) -> - #xmlel{name = <<"TEL">>, attrs = [], + #xmlel{name = <<"TEL">>, children = - [#xmlel{name = <<"VOICE">>, attrs = [], children = []}, - #xmlel{name = <<"WORK">>, attrs = [], children = []}, - #xmlel{name = <<"NUMBER">>, attrs = [], - children = [{xmlcdata, Value}]}]}; + [#xmlel{name = <<"VOICE">>}, + #xmlel{name = <<"WORK">>}, + #xmlel{name = <<"NUMBER">>, + children = [#xmlcdata{content = Value}]}]}; ldap_attribute_to_vcard(vCard, {<<"email">>, Value}) -> - #xmlel{name = <<"EMAIL">>, attrs = [], + #xmlel{name = <<"EMAIL">>, children = - [#xmlel{name = <<"INTERNET">>, attrs = [], - children = []}, - #xmlel{name = <<"PREF">>, attrs = [], children = []}, - #xmlel{name = <<"USERID">>, attrs = [], - children = [{xmlcdata, Value}]}]}; + [#xmlel{name = <<"INTERNET">>}, + #xmlel{name = <<"PREF">>}, + #xmlel{name = <<"USERID">>, + children = [#xmlcdata{content = Value}]}]}; ldap_attribute_to_vcard(vCard, {<<"photo">>, Value}) -> - #xmlel{name = <<"PHOTO">>, attrs = [], + #xmlel{name = <<"PHOTO">>, children = - [#xmlel{name = <<"TYPE">>, attrs = [], - children = [{xmlcdata, <<"image/jpeg">>}]}, - #xmlel{name = <<"BINVAL">>, attrs = [], - children = [{xmlcdata, base64:encode(Value)}]}]}; + [#xmlel{name = <<"TYPE">>, + children = [#xmlcdata{content = <<"image/jpeg">>}]}, + #xmlel{name = <<"BINVAL">>, + children = [#xmlcdata{content = base64:encode(Value)}]}]}; ldap_attribute_to_vcard(vCardN, {<<"family">>, Value}) -> - #xmlel{name = <<"FAMILY">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"FAMILY">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCardN, {<<"given">>, Value}) -> - #xmlel{name = <<"GIVEN">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"GIVEN">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCardN, {<<"middle">>, Value}) -> - #xmlel{name = <<"MIDDLE">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"MIDDLE">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCardO, {<<"orgname">>, Value}) -> - #xmlel{name = <<"ORGNAME">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"ORGNAME">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCardO, {<<"orgunit">>, Value}) -> - #xmlel{name = <<"ORGUNIT">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"ORGUNIT">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCardA, {<<"locality">>, Value}) -> - #xmlel{name = <<"LOCALITY">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"LOCALITY">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCardA, {<<"street">>, Value}) -> - #xmlel{name = <<"STREET">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"STREET">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCardA, {<<"ctry">>, Value}) -> - #xmlel{name = <<"CTRY">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"CTRY">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCardA, {<<"region">>, Value}) -> - #xmlel{name = <<"REGION">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"REGION">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(vCardA, {<<"pcode">>, Value}) -> - #xmlel{name = <<"PCODE">>, attrs = [], - children = [{xmlcdata, Value}]}; + #xmlel{name = <<"PCODE">>, + children = [#xmlcdata{content = Value}]}; ldap_attribute_to_vcard(_, _) -> none. search_internal(_, []) -> diff --git a/test/acc_SUITE.erl b/test/acc_SUITE.erl index 255e5721bfa..f86bea5a2e2 100644 --- a/test/acc_SUITE.erl +++ b/test/acc_SUITE.erl @@ -199,16 +199,19 @@ strip_with_params(_Config) -> ?assertEqual(NewHostType, mongoose_acc:host_type(NAcc2)). sample_stanza() -> - {xmlel, <<"iq">>, - [{<<"xml:lang">>, <<"en">>}, - {<<"type">>, <<"set">>}, - {<<"from">>, <<"a@localhost">>}, - {<<"to">>, <<"a@localhost">>}], - [{xmlel, <<"block">>, - [{<<"xmlns">>, <<"urn:xmpp:blocking">>}], - [{xmlel, <<"item">>, - [{<<"jid">>, <<"bob37.814302@localhost">>}], - []}]}]}. + #xmlel{name = <<"iq">>, + attrs = #{<<"xml:lang">> => <<"en">>, + <<"type">> => <<"set">>, + <<"from">> => <<"a@localhost">>, + <<"to">> => <<"a@localhost">>}, + children = [ + #xmlel{name = <<"block">>, + attrs = #{<<"xmlns">> => <<"urn:xmpp:blocking">>}, + children = [ + #xmlel{name = <<"item">>, + attrs = #{<<"jid">> => <<"bob37.814302@localhost">>}} + ]} + ]}. stanza_with_cdata() -> @@ -219,21 +222,23 @@ stanza_with_cdata() -> iq_stanza() -> - {xmlel,<<"iq">>, - [{<<"type">>,<<"set">>}, - {<<"id">>,<<"a31baa4c478896af19b76bac799b65ed">>}, - {<<"from">>, <<"a@localhost">>}, - {<<"to">>, <<"localhost">>}], - [{xmlel,<<"session">>, - [{<<"xmlns">>,<<"urn:ietf:params:xml:ns:xmpp-session">>}], - []}]}. + #xmlel{ name = <<"iq">>, + attrs = #{<<"type">> => <<"set">>, + <<"id">> => <<"a31baa4c478896af19b76bac799b65ed">>, + <<"from">> => <<"a@localhost">>, + <<"to">> => <<"localhost">>}, + children = [ + #xmlel{ name = <<"session">>, + attrs = #{<<"xmlns">> => <<"urn:ietf:params:xml:ns:xmpp-session">>}} + ]}. another_iq_stanza() -> - {xmlel,<<"iq">>, - [{<<"type">>,<<"pet">>}, - {<<"id">>,<<"a31baa4c478896af19b76bac799b65ed">>}, - {<<"from">>, <<"a@localhost">>}, - {<<"to">>, <<"localhost">>}], - [{xmlel,<<"session">>, - [{<<"xmlns">>,<<"urn:ietf:params:xml:ns:xmpp-session">>}], - []}]}. + #xmlel{ name = <<"iq">>, + attrs = #{<<"type">> => <<"pet">>, + <<"id">> => <<"a31baa4c478896af19b76bac799b65ed">>, + <<"from">> => <<"a@localhost">>, + <<"to">> => <<"localhost">>}, + children = [ + #xmlel{ name = <<"session">>, + attrs = #{<<"xmlns">> => <<"urn:ietf:params:xml:ns:xmpp-session">>}} + ]}. diff --git a/test/adhoc_SUITE.erl b/test/adhoc_SUITE.erl index bd72cdedba6..62aef9d68bd 100644 --- a/test/adhoc_SUITE.erl +++ b/test/adhoc_SUITE.erl @@ -97,28 +97,25 @@ produce_response_full(_C) -> }, ExpectedActionsEls = [#xmlel{ name = <<"actions">>, - attrs = [{<<"execute">>, <<"next">>}], + attrs = #{<<"execute">> => <<"next">>}, children = [#xmlel{name = Action} || Action <- Actions] }], ExpectedNotesEls = [ #xmlel{ name = <<"note">>, - attrs = [{<<"type">>, Type}], + attrs = #{<<"type">> => Type}, children = [#xmlcdata{content = Text}] } || {Type, Text} <- Notes ], ExpectedChildren = ExpectedActionsEls ++ ExpectedNotesEls ++ AdditionalElements, % when - #xmlel{ - name = <<"command">>, - attrs = Attrs, - children = Children - } = adhoc:produce_response(AdhocResponse), + #xmlel{ name = <<"command">>, children = Children } = + Resp = adhoc:produce_response(AdhocResponse), % then - ?assertEqual(<<"1234">>, proplists:get_value(<<"sessionid">>, Attrs)), - ?assertEqual(<<"node_name">>, proplists:get_value(<<"node">>, Attrs)), - ?assertEqual(<<"executing">>, proplists:get_value(<<"status">>, Attrs)), + ?assertEqual(<<"1234">>, exml_query:attr(Resp, <<"sessionid">>)), + ?assertEqual(<<"node_name">>, exml_query:attr(Resp, <<"node">>)), + ?assertEqual(<<"executing">>, exml_query:attr(Resp, <<"status">>)), ?assertEqual(lists:sort(ExpectedChildren), lists:sort(Children)). produce_response_no_session_id(_C) -> @@ -132,7 +129,7 @@ produce_response_no_session_id(_C) -> attrs = Attrs } = adhoc:produce_response(AdhocResponse), % then - SessionID = proplists:get_value(<<"sessionid">>, Attrs), + SessionID = maps:get(<<"sessionid">>, Attrs, undefined), ?assert(is_binary(SessionID)), ?assertNotEqual(<<>>, SessionID). @@ -157,7 +154,6 @@ produce_response_no_default_action(_C) -> }, ExpectedActionsEls = [#xmlel{ name = <<"actions">>, - attrs = [], children = [#xmlel{name = Action} || Action <- [<<"next">> | Actions]] }], % when @@ -177,7 +173,7 @@ produce_response_default_action_not_present(_C) -> }, ExpectedActionsEls = [#xmlel{ name = <<"actions">>, - attrs = [{<<"execute">>, <<"prev">>}], + attrs = #{<<"execute">> => <<"prev">>}, children = [#xmlel{name = Action} || Action <- [<<"prev">> | Actions]] }], % when @@ -195,10 +191,10 @@ produce_response_default_action_not_present(_C) -> sample_form() -> #xmlel{ name = <<"x">>, - attrs = [ - {<<"xmlns">>, <<"jabber:x:data">>}, - {<<"type">>, <<"form">>} - ], + attrs = #{ + <<"xmlns">> => <<"jabber:x:data">>, + <<"type">> => <<"form">> + }, children = [] }. @@ -210,11 +206,11 @@ sample_request(MaybeForm) -> type = set, lang = <<"en-us">>, sub_el = #xmlel{ - attrs = [ - {<<"node">>, <<"node_name">>}, - {<<"sessionid">>, <<"1">>}, - {<<"action">>, <<"execute">>} - ], + attrs = #{ + <<"node">> => <<"node_name">>, + <<"sessionid">> => <<"1">>, + <<"action">> => <<"execute">> + }, children = [#xmlel{name = <<"test">>}] ++ MaybeForm }, xmlns = ?NS_COMMANDS @@ -222,7 +218,7 @@ sample_request(MaybeForm) -> is_bad_request(#xmlel{ name = <<"error">>, - attrs = [{<<"code">>, <<"400">>}, {<<"type">>, <<"modify">>}], + attrs = #{<<"code">> := <<"400">>, <<"type">> := <<"modify">>}, children = [#xmlel{name = <<"bad-request">>}] }) -> true; diff --git a/test/amp_SUITE.erl b/test/amp_SUITE.erl index 327d39de329..55b27ef9efd 100644 --- a/test/amp_SUITE.erl +++ b/test/amp_SUITE.erl @@ -180,47 +180,43 @@ extract_incomplete_amp_test(_) -> strip_amp_el_test(_) -> AmpEl = #xmlel{name = <<"amp">>, - attrs = [{<<"xmlns">>,<<"http://jabber.org/protocol/amp">>}, - {<<"status">>,<<"notify">>}, - {<<"to">>,<<"bernardo@hamlet.lit/elsinore">>}, - {<<"from">>,<<"francisco@hamlet.lit">>}], + attrs = #{<<"xmlns">> => <<"http://jabber.org/protocol/amp">>, + <<"status">> => <<"notify">>, + <<"to">> => <<"bernardo@hamlet.lit/elsinore">>, + <<"from">> => <<"francisco@hamlet.lit">>}, children = [ #xmlel{name = <<"rule">>, - attrs = [{<<"action">>,<<"notify">>}, - {<<"condition">>,<<"deliver">>}, - {<<"value">>,<<"stored">>}]}]}, + attrs = #{<<"action">> => <<"notify">>, + <<"condition">> => <<"deliver">>, + <<"value">> => <<"stored">>}}]}, BodyEl = #xmlel{name = <<"body">>, - attrs = [], children = [#xmlcdata{content = <<"Hello there!">>}]}, M = #xmlel{name = <<"message">>, attrs = - [{<<"from">>,<<"hamlet.lit">>}, - {<<"to">>,<<"bernardo@hamlet.lit/elsinore">>}, - {<<"id">>,<<"chatty2">>}], + #{<<"from">> => <<"hamlet.lit">>, + <<"to">> => <<"bernardo@hamlet.lit/elsinore">>, + <<"id">> => <<"chatty2">>}, children = [AmpEl,BodyEl]}, ?assertEqual( #xmlel{name = <<"message">>, - attrs = [{<<"from">>, <<"hamlet.lit">>}, - {<<"to">>, <<"bernardo@hamlet.lit/elsinore">>}, - {<<"id">>, <<"chatty2">>}], + attrs = #{<<"from">> => <<"hamlet.lit">>, + <<"to">> => <<"bernardo@hamlet.lit/elsinore">>, + <<"id">> => <<"chatty2">>}, children = [BodyEl] }, amp:strip_amp_el(M)). strip_amp_el_noop_test(_) -> BodyEl = #xmlel{name = <<"body">>, - attrs = [], children = [#xmlcdata{content = <<"Hello there!">>}]}, M = #xmlel{name = <<"message">>, attrs = - [{<<"from">>,<<"hamlet.lit">>}, - {<<"to">>,<<"bernardo@hamlet.lit/elsinore">>}, - {<<"id">>,<<"chatty2">>}], + #{<<"from">> => <<"hamlet.lit">>, + <<"to">> => <<"bernardo@hamlet.lit/elsinore">>, + <<"id">> => <<"chatty2">>}, children = [BodyEl]}, ?assertEqual(M, amp:strip_amp_el(M)). is_valid_rule(#amp_rule{}) -> true; is_valid_rule(#amp_invalid_rule{}) -> false. - - diff --git a/test/auth_tokens_SUITE.erl b/test/auth_tokens_SUITE.erl index c12e936e3e5..328505479d8 100644 --- a/test/auth_tokens_SUITE.erl +++ b/test/auth_tokens_SUITE.erl @@ -111,8 +111,22 @@ validation_test(Config) -> validation_test(_, ExampleToken) -> %% given Serialized = ?TESTED:serialize(ExampleToken), + ct:pal("ExampleToken:~n ~p", [ExampleToken]), + %% note that mod_auth_token:deserialize/1 recomputes token_body. + %% therefore the supplied MAC signature (which is part of the serialized data) + %% may become invalid if the vcard xml binary data changes after running + %% exml:parse/1 and exml:to_binary/1 on it. + DeserialisedToken = ?TESTED:deserialize(Serialized), + ct:pal("DeserialisedToken:~n ~p", [DeserialisedToken]), + TokenWithMac = ?TESTED:token_with_mac(host_type(), + DeserialisedToken#token{ + mac_signature = undefined, + token_body = undefined}), + ct:pal("TokenWithMac:~n ~p", [TokenWithMac]), %% when Result = ?TESTED:authenticate(host_type(), Serialized), + ct:pal("Result: ~p", [Result]), + %% then ?ae(true, is_validation_success(Result)). @@ -231,62 +245,73 @@ mock_tested_backend() -> end). provision_token_example() -> - {token,provision, - {{2055,10,27},{10,54,22}}, - {jid,<<"cee2m1s0i">>,domain(),<<>>}, - undefined, - {xmlel,<<"vCard">>, - [{<<"sgzldnl">>,<<"inxdutpu">>}, - {<<"scmgsrfi">>,<<"nhgybwu">>}, - {<<"ixrsmzee">>,<<"rysdh">>}, - {<<"oxwothgyei">>,<<"wderkfgexv">>}], - [{xmlel,<<"nqe">>, - [{<<"i">>,<<"u">>}, - {<<"gagnixjgml">>,<<"odaorofnra">>}, - {<<"ijz">>,<<"zvbrqnybi">>}], - [{xmlcdata,<<"uprmzqf">>}, - {xmlel,<<"lnnitxm">>, - [{<<"qytehi">>,<<"axl">>}, - {<<"xaxforb">>,<<"jrdeydsqhj">>}], - []}, - {xmlcdata,<<"pncgsaxl">>}, - {xmlel,<<"jfofazuau">>,[{<<"si">>,<<"l">>}],[]}]}, - {xmlel,<<"moy">>, - [{<<"femjc">>,<<"qqb">>},{<<"tirfmekvpk">>,<<"sa">>}], - []}, - {xmlcdata,<<"bgxlyqdeeuo">>}]}, - <<40,147,30,116,208,228,12,231,163,180,143,193,209,7,131,166, - 44,123,76,50,14,34,31,163,142,88,138,73,220,190,130,60,151, - 113,46,103,66,94,187,90,137,184,0,64,114,199,73,150>>, - <<112,114,111,118,105,115,105,111,110,0,99,69,69,50,77,49,83,48,73, - 64,108,111,99,97,108,104,111,115,116,0,54,52,56,55,53,52,54,54,52, - 54,50,0,60,118,67,97,114,100,32,115,103,122,108,100,110,108,61,39, - 105,110,120,100,117,116,112,117,39,32,115,99,109,103,115,114,102, - 105,61,39,110,104,103,121,98,119,117,39,32,105,120,114,115,109, - 122,101,101,61,39,114,121,115,100,104,39,32,111,120,119,111,116, - 104,103,121,101,105,61,39,119,100,101,114,107,102,103,101,120,118, - 39,62,60,110,113,101,32,105,61,39,117,39,32,103,97,103,110,105, - 120,106,103,109,108,61,39,111,100,97,111,114,111,102,110,114,97, - 39,32,105,106,122,61,39,122,118,98,114,113,110,121,98,105,39,62, - 117,112,114,109,122,113,102,60,108,110,110,105,116,120,109,32,113, - 121,116,101,104,105,61,39,97,120,108,39,32,120,97,120,102,111,114, - 98,61,39,106,114,100,101,121,100,115,113,104,106,39,47,62,112,110, - 99,103,115,97,120,108,60,106,102,111,102,97,122,117,97,117,32,115, - 105,61,39,108,39,47,62,60,47,110,113,101,62,60,109,111,121,32,102, - 101,109,106,99,61,39,113,113,98,39,32,116,105,114,102,109,101,107, - 118,112,107,61,39,115,97,39,47,62,98,103,120,108,121,113,100,101, - 101,117,111,60,47,118,67,97,114,100,62>>}. + #token{ + type = provision, + expiry_datetime = {{2055,10,27},{10,54,22}}, + user_jid = jid:make(<<"cee2m1s0i">>,domain(),<<>>), + sequence_no = undefined, + vcard = #xmlel{ + name = <<"vCard">>, + attrs = #{<<"sgzldnl">> => <<"inxdutpu">>, + <<"scmgsrfi">> => <<"nhgybwu">>, + <<"ixrsmzee">> => <<"rysdh">>, + <<"oxwothgyei">> => <<"wderkfgexv">>}, + children = [ + #xmlel{ + name = <<"nqe">>, + attrs = #{<<"i">> => <<"u">>, + <<"gagnixjgml">> => <<"odaorofnra">>, + <<"ijz">> => <<"zvbrqnybi">>}, + children = [ + #xmlcdata{content = <<"uprmzqf">>}, + #xmlel{name = <<"lnnitxm">>, + attrs = #{<<"qytehi">> => <<"axl">>, + <<"xaxforb">> => <<"jrdeydsqhj">>}}, + #xmlcdata{content = <<"pncgsaxl">>}, + #xmlel{name = <<"jfofazuau">>, + attrs = #{<<"si">> => <<"l">>}} + ]}, + #xmlel{name = <<"moy">>, + attrs = #{<<"femjc">> => <<"qqb">>, + <<"tirfmekvpk">> => <<"sa">>}}, + #xmlcdata{content = <<"bgxlyqdeeuo">>} + ]}, + mac_signature = <<96,213,61,178,182,8,167,202,120,67,82,228,108,171,74,98,88,236, + 200,77,44,151,199,213,43,193,109,139,197,14,179,107,72,243,50, + 199,208,14,254,218,47,164,249,1,212,167,90,218>>, + token_body = <<112,114,111,118,105,115,105,111,110,0,99,101,101,50,109,49, + 115,48,105,64,108,111,99,97,108,104,111,115,116,0,54,52,56, + 55,53,52,54,54,52,54,50,0,60,118,67,97,114,100,32,105,120, + 114,115,109,122,101,101,61,39,114,121,115,100,104,39,32,111, + 120,119,111,116,104,103,121,101,105,61,39,119,100,101,114, + 107,102,103,101,120,118,39,32,115,99,109,103,115,114,102,105, + 61,39,110,104,103,121,98,119,117,39,32,115,103,122,108,100, + 110,108,61,39,105,110,120,100,117,116,112,117,39,62,60,110, + 113,101,32,103,97,103,110,105,120,106,103,109,108,61,39,111, + 100,97,111,114,111,102,110,114,97,39,32,105,61,39,117,39,32, + 105,106,122,61,39,122,118,98,114,113,110,121,98,105,39,62, + 117,112,114,109,122,113,102,60,108,110,110,105,116,120,109, + 32,113,121,116,101,104,105,61,39,97,120,108,39,32,120,97,120, + 102,111,114,98,61,39,106,114,100,101,121,100,115,113,104,106, + 39,47,62,112,110,99,103,115,97,120,108,60,106,102,111,102,97, + 122,117,97,117,32,115,105,61,39,108,39,47,62,60,47,110,113, + 101,62,60,109,111,121,32,102,101,109,106,99,61,39,113,113,98, + 39,32,116,105,114,102,109,101,107,118,112,107,61,39,115,97, + 39,47,62,98,103,120,108,121,113,100,101,101,117,111,60,47, + 118,67,97,114,100,62>>}. refresh_token_example() -> - {token,refresh, - {{2055,10,27},{10,54,14}}, - {jid,<<"a">>,domain(),<<>>}, - 4,undefined, - <<151,225,117,181,0,168,228,208,238,182,157,253,24,200,231,25,189, - 160,176,144,85,193,20,108,31,23,46,35,215,41,250,57,68,201,45,33, - 241,219,197,83,155,118,217,92,172,42,8,118>>, - <<114,101,102,114,101,115,104,0,97,64,108,111,99,97,108,104,111,115, - 116,0,54,52,56,55,53,52,54,54,52,53,52,0,52>>}. + #token{ + type = refresh, + expiry_datetime = {{2055,10,27},{10,54,14}}, + user_jid = jid:make(<<"a">>,domain(),<<>>), + sequence_no = 4, + vcard = undefined, + mac_signature = <<151,225,117,181,0,168,228,208,238,182,157,253,24,200,231,25,189, + 160,176,144,85,193,20,108,31,23,46,35,215,41,250,57,68,201,45,33, + 241,219,197,83,155,118,217,92,172,42,8,118>>, + token_body = <<114,101,102,114,101,115,104,0,97,64,108,111,99,97,108,104,111,115, + 116,0,54,52,56,55,53,52,54,54,52,53,52,0,52>>}. %% %% Generators diff --git a/test/carboncopy_proper_tests_SUITE.erl b/test/carboncopy_proper_tests_SUITE.erl index 93e8cb1bfdf..c4b37229bd3 100644 --- a/test/carboncopy_proper_tests_SUITE.erl +++ b/test/carboncopy_proper_tests_SUITE.erl @@ -92,51 +92,49 @@ alice() -> %% non_chat_message() -> - xmlel("message", [], []). + xmlel("message", #{}, []). private_carbon_message() -> xmlel("message", - [{<<"type">>, <<"chat">>}], - [xmlel("private", [{<<"xmlns">>, <<"urn:xmpp:carbons:2">>}], [])]). + #{<<"type">> => <<"chat">>}, + [xmlel("private", #{<<"xmlns">> => <<"urn:xmpp:carbons:2">>}, [])]). no_copy_message() -> xmlel("message", - [{<<"type">>, <<"chat">>}], - [xmlel("no-copy", [{<<"xmlns">>, <<"urn:xmpp:hints">>}], [])]). + #{<<"type">> => <<"chat">>}, + [xmlel("no-copy", #{<<"xmlns">> => <<"urn:xmpp:hints">>}, [])]). received_message() -> xmlel("message", - [{<<"type">>, <<"chat">>}], - [xmlel("received", [{<<"xmlns">>, <<"urn:xmpp:carbons:2">>}], [])]). + #{<<"type">> => <<"chat">>}, + [xmlel("received", #{<<"xmlns">> => <<"urn:xmpp:carbons:2">>}, [])]). sent_message() -> xmlel("message", - [{<<"type">>, <<"chat">>}], - [xmlel("sent", [{<<"xmlns">>, <<"urn:xmpp:carbons:2">>}], [])]). + #{<<"type">> => <<"chat">>}, + [xmlel("sent", #{<<"xmlns">> => <<"urn:xmpp:carbons:2">>}, [])]). simple_chat_message() -> - xmlel("message", [{<<"type">>, <<"chat">>}], []). + xmlel("message", #{<<"type">> => <<"chat">>}, []). chat_state_notification() -> xmlel("message", - [{<<"type">>, <<"chat">>}], - [xmlel("someelement", [{<<"xmlns">>, <<"http://jabber.org/protocol/chatstates">>}], [])]). + #{<<"type">> => <<"chat">>}, + [xmlel("someelement", #{<<"xmlns">> => <<"http://jabber.org/protocol/chatstates">>}, [])]). delivery_receipt() -> xmlel("message", - [{<<"type">>, <<"chat">>}], - [xmlel("received", [{<<"xmlns">>, <<"urn:xmpp:receipts">>}], [])]). + #{<<"type">> => <<"chat">>}, + [xmlel("received", #{<<"xmlns">> => <<"urn:xmpp:receipts">>}, [])]). muc_invitation() -> - xmlel("message", - [{<<"type">>, <<"chat">>}], - [xmlel("x", [{<<"xmlns">>, <<"jabber:x:conference">>}], - [xmlel("invite", [<<"from">>], [<<"alice@localhost">>])])]). + xmlel("message", #{}, + [xmlel("x", #{<<"xmlns">> => <<"http://jabber.org/protocol/muc#user">>}, + [xmlel("invite", #{<<"from">> => <<"crone1@shakespeare.lit/desktop">>}, [])])]). direct_invitation() -> - xmlel("message", - [{<<"type">>, <<"chat">>}], - [xmlel("x", [{<<"xmlns">>, <<"jabber:x:conference">>}], [])]). + xmlel("message", #{}, + [xmlel("x", #{<<"xmlns">> => <<"jabber:x:conference">>}, [])]). badarg_message() -> - xmlel("message", [{<<"type">>, <<"123">>}],[]). + xmlel("message", #{<<"type">> => <<"123">>},[]). diff --git a/test/event_pusher_sns_SUITE.erl b/test/event_pusher_sns_SUITE.erl index fad07555478..8c2d4735e87 100644 --- a/test/event_pusher_sns_SUITE.erl +++ b/test/event_pusher_sns_SUITE.erl @@ -236,8 +236,9 @@ message(From, Recipient, Type, Body) -> _ -> [#xmlel{name = <<"body">>, children = [#xmlcdata{content = Body}]}] end, #xmlel{name = <<"message">>, - attrs = [{<<"from">>, jid:to_binary(From)}, {<<"type">>, Type}, - {<<"to">>, jid:to_binary(Recipient)}], + attrs = #{<<"from">> => jid:to_binary(From), + <<"type">> => Type, + <<"to">> => jid:to_binary(Recipient)}, children = Children}. host_type() -> diff --git a/test/jlib_SUITE.erl b/test/jlib_SUITE.erl index e687a9e3554..75e76416f31 100644 --- a/test/jlib_SUITE.erl +++ b/test/jlib_SUITE.erl @@ -28,8 +28,8 @@ make_iq_reply_switches_to_and_from_attrs(_C) -> FromJid = <<"test2@esl.com/res2">>, #xmlel{attrs = Attrs} = BaseIQ = base_iq(), - IQWithToAndFrom = BaseIQ#xmlel{attrs = [{<<"to">>, ToJid}, - {<<"from">>, FromJid} | Attrs]}, + IQWithToAndFrom = BaseIQ#xmlel{attrs = Attrs#{<<"to">> => ToJid, + <<"from">> => FromJid}}, WithToFromReply = jlib:make_result_iq_reply(IQWithToAndFrom), @@ -40,7 +40,7 @@ make_iq_reply_switches_to_and_from_attrs(_C) -> make_iq_reply_switches_from_to_to(_C) -> FromJid = <<"test2@esl.com/res2">>, #xmlel{attrs = Attrs} = BaseIQ = base_iq(), - IQWithFrom = BaseIQ#xmlel{attrs = [{<<"from">>, FromJid} | Attrs]}, + IQWithFrom = BaseIQ#xmlel{attrs = Attrs#{<<"from">> => FromJid}}, WithFromReply = jlib:make_result_iq_reply(IQWithFrom), @@ -50,7 +50,7 @@ make_iq_reply_switches_from_to_to(_C) -> make_iq_reply_changes_to_to_from(_C) -> ToJid = <<"test@esl.com/res">>, #xmlel{attrs = Attrs} = BaseIQ = base_iq(), - IQWithTo = BaseIQ#xmlel{attrs = [{<<"to">>, ToJid} | Attrs]}, + IQWithTo = BaseIQ#xmlel{attrs = Attrs#{<<"to">> => ToJid}}, WithToReply = jlib:make_result_iq_reply(IQWithTo), @@ -80,11 +80,11 @@ error_reply_check(_) -> base_iq() -> #xmlel{name = <<"iq">>, - attrs = [{<<"id">>, base64:encode(crypto:strong_rand_bytes(4))}, - {<<"xmlns">>, <<"jabber:client">>}, - {<<"type">>, <<"set">>}], + attrs = #{<<"id">> => base64:encode(crypto:strong_rand_bytes(4)), + <<"xmlns">> => <<"jabber:client">>, + <<"type">> => <<"set">>}, children = [#xmlel{name = <<"session">>, - attrs = [{<<"xmlns">>, <<"urn:ietf:params:xml:ns:xmpp-session">>}]} + attrs = #{<<"xmlns">> => <<"urn:ietf:params:xml:ns:xmpp-session">>}} ]}. element_length_is_too_big(Els) -> @@ -95,4 +95,3 @@ run_property(Prop, NumTest, StartSize, StopSize) -> {numtests, NumTest}, {start_size, StartSize}, {max_size, StopSize}])). - diff --git a/test/json_formatter_SUITE.erl b/test/json_formatter_SUITE.erl index 9e15aa57170..10f03eb87eb 100644 --- a/test/json_formatter_SUITE.erl +++ b/test/json_formatter_SUITE.erl @@ -18,6 +18,7 @@ -include_lib("kernel/include/logger.hrl"). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include_lib("exml/include/exml.hrl"). -define(LOGFILE, "log/mongooseim.log"). -define(HID, json_log). @@ -128,6 +129,7 @@ acc_is_formatted(Config) -> Body = <<"JSON-match-this-acc">>, Acc = example_acc(Body), + #{stanza := #{ element := Elem}} = Acc, ?LOG_INFO(#{what => routing_result, acc => Acc, routing_modules => [mongoose_router_1, mongoose_router_2], routing_result => [{{inside, two_tuples}}, {inside, one_tuple}]}), @@ -154,12 +156,13 @@ acc_is_formatted(Config) -> <<"from_jid">> := <<"usera@localhost">>, <<"origin_pid">> := Pid, % format_packet_filter/2 changes the packet - <<"packet">> := <<"JSON-match-this-acc">>, + <<"packet">> := Packet, <<"routing_modules">> := [<<"mongoose_router_1">>, <<"mongoose_router_2">>], <<"routing_result">> := [<<"{{inside,two_tuples}}">>,<<"{inside,one_tuple}">>], <<"to_jid">> := <<"userb@localhost">>, <<"what">> := <<"routing_result">>} = Decoded, + ?assertEqual({ok, Elem}, exml:parse(Packet)), ?assert(is_integer(calendar:rfc3339_to_system_time(binary_to_list(DateTimeStrBin)))), ?assert(is_integer(calendar:rfc3339_to_system_time(binary_to_list(DateTimeStrBin2)))), Pid = unicode:characters_to_binary(pid_to_list(self())). @@ -172,6 +175,7 @@ acc_is_preserved(Config) -> Body = <<"JSON-match-this-preserve-acc">>, Acc = example_acc(Body), + #{stanza := #{ element := Elem}} = Acc, ?LOG_INFO(#{what => routing_result, acc => Acc, routing_modules => [mongoose_router_1, mongoose_router_2], routing_result => [{{inside, two_tuples}}, {inside, one_tuple}]}), @@ -199,15 +203,15 @@ acc_is_preserved(Config) -> <<"from_jid">> := <<"usera@localhost">>, <<"origin_pid">> := Pid, % format_packet_filter/2 changes the packet - <<"packet">> := <<"JSON-match-this-preserve-acc">>, + <<"packet">> := Packet, <<"routing_modules">> := [<<"mongoose_router_1">>, <<"mongoose_router_2">>], <<"routing_result">> := [<<"{{inside,two_tuples}}">>,<<"{inside,one_tuple}">>], <<"to_jid">> := <<"userb@localhost">>, <<"what">> := <<"routing_result">>} = Decoded, - % This is not ideal but that's how the filter behaves A = iolist_to_binary(io_lib:format("~0p", [Acc])), + ?assertEqual({ok, Elem}, exml:parse(Packet)), ?assert(is_integer(calendar:rfc3339_to_system_time(binary_to_list(DateTimeStrBin)))), ?assert(is_integer(calendar:rfc3339_to_system_time(binary_to_list(DateTimeStrBin2)))), Pid = unicode:characters_to_binary(pid_to_list(self())). @@ -346,9 +350,11 @@ large_event_dont_crash_formatter(_Config) -> %% example_acc(Body) -> - Elem = {xmlel, <<"message">>, - [{<<"type">>, <<"chat">>}, {<<"id">>, <<"1111">>}], - [{xmlel, <<"body">>, [], [{xmlcdata, Body}]}]}, + Elem = #xmlel{name = <<"message">>, + attrs = #{<<"type">> => <<"chat">>, + <<"id">> => <<"1111">>}, + children = [#xmlel{name = <<"body">>, + children = [#xmlcdata{content = Body}]}]}, #{lserver => <<"localhost">>, mongoose_acc => true, non_strippable => [], diff --git a/test/mam_misc_SUITE.erl b/test/mam_misc_SUITE.erl index f85e4c8478b..2e8da324b51 100644 --- a/test/mam_misc_SUITE.erl +++ b/test/mam_misc_SUITE.erl @@ -166,24 +166,24 @@ maybe_get({Elem, XmlElem, Maybe}, _, MustNotContain) -> %% Possible XML elements attrs(From, To, Type) -> - [{<<"from">>, From}, {<<"to">>, To}, {<<"type">>, Type}]. + #{<<"from">> => From, <<"to">> => To, <<"type">> => Type}. body() -> #xmlel{name = <<"body">>, children = [#xmlcdata{content = bin()}]}. chat_marker() -> - #xmlel{name = <<"displayed">>, attrs = [{<<"xmlmn">>, ?NS_CHAT_MARKERS}, {<<"id">>, bin()}]}. + #xmlel{name = <<"displayed">>, attrs = #{<<"xmlmn">> => ?NS_CHAT_MARKERS, <<"id">> => bin()}}. retraction() -> #xmlel{name = <<"apply-to">>, - attrs = [{<<"id">>, bin()}, {<<"xmlns">>, ?NS_FASTEN}], - children = [#xmlel{name = <<"retract">>, attrs = [{<<"xmlns">>, ?NS_RETRACT}]}]}. + attrs = #{<<"id">> => bin(), <<"xmlns">> => ?NS_FASTEN}, + children = [#xmlel{name = <<"retract">>, attrs = #{<<"xmlns">> => ?NS_RETRACT}}]}. mam_result() -> #xmlel{name = <<"result">>, - attrs = [{<<"id">>, bin()}, {<<"queryid">>, bin()}, {<<"xmlns">>, ?NS_MAM_06}]}. + attrs = #{<<"id">> => bin(), <<"queryid">> => bin(), <<"xmlns">> => ?NS_MAM_06}}. offline_delay() -> - #xmlel{name = <<"delay">>, attrs = [{<<"stamp">>, bin()}, {<<"xmlns">>, ?NS_DELAY}]}. + #xmlel{name = <<"delay">>, attrs = #{<<"stamp">> => bin(), <<"xmlns">> => ?NS_DELAY}}. no_store() -> - #xmlel{name = <<"no-store">>, attrs = [{<<"xmlns">>, ?NS_HINTS}]}. + #xmlel{name = <<"no-store">>, attrs = #{<<"xmlns">> => ?NS_HINTS}}. store() -> - #xmlel{name = <<"store">>, attrs = [{<<"xmlns">>, ?NS_HINTS}]}. + #xmlel{name = <<"store">>, attrs = #{<<"xmlns">> => ?NS_HINTS}}. packet(Name, Attrs, Children) -> #xmlel{name = Name, attrs = Attrs, children = Children}. diff --git a/test/mod_global_distrib_SUITE.erl b/test/mod_global_distrib_SUITE.erl index 69ea0b3cd66..8fe58a66fb8 100644 --- a/test/mod_global_distrib_SUITE.erl +++ b/test/mod_global_distrib_SUITE.erl @@ -146,7 +146,9 @@ fake_acc_to_component(From) -> }, Packet = #xmlel{ name = <<"message">>, - attrs = [{<<"from">>, FromBin}, {<<"to">>, ToBin}, {<<"type">>, <<"chat">>}], + attrs = #{<<"from">> => FromBin, + <<"to">> => ToBin, + <<"type">> => <<"chat">>}, children = [BodyEl] }, {mongoose_acc:new(#{ location => ?LOCATION, diff --git a/test/privacy_SUITE.erl b/test/privacy_SUITE.erl index dc1c78fa897..0546050508b 100644 --- a/test/privacy_SUITE.erl +++ b/test/privacy_SUITE.erl @@ -149,9 +149,12 @@ userlist(_) -> presence() -> - {xmlel, <<"presence">>, [{<<"xml:lang">>, <<"en">>}], []}. + #xmlel{name = <<"presence">>, + attrs = #{<<"xml:lang">> => <<"en">>}, + children = []}. message() -> - {xmlel, <<"message">>, - [{<<"type">>, <<"chat">>}, {<<"to">>, <<"bob@localhost">>}], - [{xmlel, <<"body">>, [], [{xmlcdata, <<"roar!">>}]}]}. + #xmlel{name = <<"message">>, + attrs = #{<<"type">> => <<"chat">>, <<"to">> => <<"bob@localhost">>}, + children = [#xmlel{name = <<"body">>, + children = [#xmlcdata{content = <<"roar!">>}]}]}. diff --git a/test/roster_SUITE.erl b/test/roster_SUITE.erl index 72df99631d9..867317673fd 100644 --- a/test/roster_SUITE.erl +++ b/test/roster_SUITE.erl @@ -191,7 +191,7 @@ host_type() -> <<"test type">>. addbob_stanza() -> #xmlel{children = [ #xmlel{ - attrs = [{<<"jid">>, bob()}], + attrs = #{<<"jid">> => bob()}, children = [ #xmlel{name = <<"group">>, children = [ diff --git a/test/router_SUITE.erl b/test/router_SUITE.erl index 3509a24380f..641551cc9c8 100644 --- a/test/router_SUITE.erl +++ b/test/router_SUITE.erl @@ -70,7 +70,9 @@ do_not_reroute_errors(_) -> From = <<"ja@localhost">>, To = <<"ty@localhost">>, Stanza = #xmlel{name = <<"iq">>, - attrs = [{<<"from">>, From}, {<<"to">>, To}, {<<"type">>, <<"get">>} ] + attrs = #{<<"from">> => From, + <<"to">> => To, + <<"type">> => <<"get">>} }, Acc = mongoose_acc:new(#{ location => ?LOCATION, lserver => <<"localhost">>, diff --git a/test/xmlel_gen.erl b/test/xmlel_gen.erl index 9718cd49ccf..72435775f83 100644 --- a/test/xmlel_gen.erl +++ b/test/xmlel_gen.erl @@ -39,19 +39,19 @@ xmlel_attrs_non_unique() -> ?LET(Len, choose(1, 5), vector(Len, xmlel_attr())). xmlel_attrs() -> - ?SUCHTHAT(Attrs, xmlel_attrs_non_unique(), - length(lists:ukeysort(1, Attrs)) == length(Attrs)). + ?LET(Attrs, xmlel_attrs_non_unique(), + maps:from_list(Attrs)). xmlel(0, FixedName, FixedAttrs, FixedChildren) -> ?LET({Attrs}, {xmlel_attrs()}, #xmlel{name = list_to_binary(FixedName), - attrs = Attrs ++ FixedAttrs, + attrs = maps:merge(Attrs, FixedAttrs), children = FixedChildren}); xmlel(Size, FixedName, FixedAttrs, FixedChildren) -> ?LET({Attrs, Children}, {xmlel_attrs(), xmlel_children(Size)}, #xmlel{name = list_to_binary(FixedName), - attrs = Attrs ++ FixedAttrs, + attrs = maps:merge(Attrs, FixedAttrs), children = join_consecutive_cdata(FixedChildren ++ Children)}). xmlel_children(Size) ->