mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-24 17:29:28 +01:00
Merge branch 'master' of github.com:processone/ejabberd
This commit is contained in:
commit
afba5bc5f5
@ -890,6 +890,12 @@ The available modules, their purpose and the options allowed by each one are:
|
||||
Handles incoming HTTP connections.\\
|
||||
Options: \texttt{captcha}, \texttt{certfile}, \texttt{default\_host}, \texttt{http\_bind}, \texttt{http\_poll},
|
||||
\texttt{request\_handlers}, \texttt{tls}, \texttt{tls\_compression}, \texttt{trusted\_proxies}, \texttt{web\_admin}\\
|
||||
\titem{\texttt{ejabberd\_xmlrpc}}
|
||||
Handles XML-RPC requests to execute ejabberd commands (\ref{eja-commands}).\\
|
||||
Options: \texttt{access\_commands}, \texttt{maxsessions}, \texttt{timeout}.\\
|
||||
You can find option explanations, example configuration in old and new format,
|
||||
and example calls in several languages in the old
|
||||
\footahref{https://raw.github.com/processone/ejabberd-contrib/master/ejabberd\_xmlrpc/README.txt}{ejabberd\_xmlrpc README.txt}
|
||||
\end{description}
|
||||
|
||||
|
||||
@ -4046,15 +4052,28 @@ Options:
|
||||
not add/remove/modify contacts,
|
||||
or subscribe/unsubscribe presence.
|
||||
By default there aren't restrictions.
|
||||
\titem{managers} \ind{options!managers}
|
||||
List of remote entities that can manage users rosters using Remote Roster Management
|
||||
(\xepref{0321}).
|
||||
The protocol sections implemented are:
|
||||
\term{4.2. The remote entity requests current user's roster}.
|
||||
\term{4.3. The user updates roster}.
|
||||
\term{4.4. The remote entity updates the user's roster}.
|
||||
A remote entity cab only get or modify roster items that have the same domain as the entity.
|
||||
Default value is: \term{[]}.
|
||||
\end{description}
|
||||
|
||||
This example configuration enables Roster Versioning with storage of current id:
|
||||
This example configuration enables Roster Versioning with storage of current id.
|
||||
The ICQ and MSN transports can get ICQ and MSN contacts, add them, or remove them for any local account:
|
||||
\begin{verbatim}
|
||||
modules:
|
||||
...
|
||||
mod_roster:
|
||||
versioning: true
|
||||
store_current_id: true
|
||||
managers:
|
||||
- "icq.example.org"
|
||||
- "msn.example.org"
|
||||
...
|
||||
\end{verbatim}
|
||||
|
||||
@ -5130,9 +5149,9 @@ with a defined number and type of calling arguments and type of result
|
||||
that is registered in the \term{ejabberd\_commands} service.
|
||||
Those commands can be defined in any Erlang module and executed using any valid frontend.
|
||||
|
||||
\ejabberd{} includes a frontend to execute \term{ejabberd commands}: the script \term{ejabberdctl}.
|
||||
\ejabberd{} includes two frontends to execute \term{ejabberd commands}: the script \term{ejabberdctl} (\ref{ejabberdctl})
|
||||
and the \term{ejabberd\_xmlrpc} listener (\ref{listened-module}).
|
||||
Other known frontends that can be installed to execute ejabberd commands in different ways are:
|
||||
\term{ejabberd\_xmlrpc} (XML-RPC service),
|
||||
\term{mod\_rest} (HTTP POST service),
|
||||
\term{mod\_shcommands} (ejabberd WebAdmin page).
|
||||
|
||||
|
@ -599,9 +599,8 @@ modules:
|
||||
##
|
||||
## Enable modules with custom options in a specific virtual host
|
||||
##
|
||||
## host_config:
|
||||
## append_host_config:
|
||||
## "localhost":
|
||||
## add:
|
||||
## modules:
|
||||
## mod_echo:
|
||||
## host: "mirror.localhost"
|
||||
|
@ -16,7 +16,7 @@ Cfg = case file:consult("vars.config") of
|
||||
Macros = lists:flatmap(
|
||||
fun({roster_gateway_workaround, true}) ->
|
||||
[{d, 'ROSTER_GATEWAY_WORKAROUND'}];
|
||||
({transient_supervisors, true}) ->
|
||||
({transient_supervisors, false}) ->
|
||||
[{d, 'NO_TRANSIENT_SUPERVISORS'}];
|
||||
({nif, true}) ->
|
||||
[{d, 'NIF'}];
|
||||
|
@ -94,7 +94,7 @@
|
||||
tls_options = [],
|
||||
authenticated = false,
|
||||
jid,
|
||||
user = "", server = ?MYNAME, resource = <<"">>,
|
||||
user = "", server = <<"">>, resource = <<"">>,
|
||||
sid,
|
||||
pres_t = ?SETS:new(),
|
||||
pres_f = ?SETS:new(),
|
||||
@ -291,7 +291,12 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
||||
DefaultLang = ?MYLANG,
|
||||
case xml:get_attr_s(<<"xmlns:stream">>, Attrs) of
|
||||
?NS_STREAM ->
|
||||
Server = jlib:nameprep(xml:get_attr_s(<<"to">>, Attrs)),
|
||||
Server =
|
||||
case StateData#state.server of
|
||||
<<"">> ->
|
||||
jlib:nameprep(xml:get_attr_s(<<"to">>, Attrs));
|
||||
S -> S
|
||||
end,
|
||||
case lists:member(Server, ?MYHOSTS) of
|
||||
true ->
|
||||
Lang = case xml:get_attr_s(<<"xml:lang">>, Attrs) of
|
||||
@ -647,6 +652,7 @@ wait_for_feature_request({xmlstreamelement, El},
|
||||
StateData#state{streamid = new_id(),
|
||||
authenticated = true,
|
||||
auth_module = AuthModule,
|
||||
sasl_state = undefined,
|
||||
user = U});
|
||||
{continue, ServerOut, NewSASLState} ->
|
||||
send_element(StateData,
|
||||
@ -804,6 +810,7 @@ wait_for_sasl_response({xmlstreamelement, El},
|
||||
StateData#state{streamid = new_id(),
|
||||
authenticated = true,
|
||||
auth_module = AuthModule,
|
||||
sasl_state = undefined,
|
||||
user = U});
|
||||
{ok, Props, ServerOut} ->
|
||||
(StateData#state.sockmod):reset_stream(StateData#state.socket),
|
||||
@ -824,6 +831,7 @@ wait_for_sasl_response({xmlstreamelement, El},
|
||||
StateData#state{streamid = new_id(),
|
||||
authenticated = true,
|
||||
auth_module = AuthModule,
|
||||
sasl_state = undefined,
|
||||
user = U});
|
||||
{continue, ServerOut, NewSASLState} ->
|
||||
send_element(StateData,
|
||||
|
@ -484,7 +484,7 @@ abort_on_driver_error(Reply, From) ->
|
||||
%% Open an ODBC database connection
|
||||
odbc_connect(SQLServer) ->
|
||||
ejabberd:start_app(odbc),
|
||||
odbc:connect(SQLServer, [{scrollable_cursors, off}]).
|
||||
odbc:connect(binary_to_list(SQLServer), [{scrollable_cursors, off}]).
|
||||
|
||||
%% == Native PostgreSQL code
|
||||
|
||||
|
@ -88,7 +88,7 @@
|
||||
|
||||
-define(SUPERVISOR_START,
|
||||
p1_fsm:start(ejabberd_s2s_in, [SockData, Opts],
|
||||
?FSMOPTS ++ fsm_limit_opts(Opts)).
|
||||
?FSMOPTS ++ fsm_limit_opts(Opts))).
|
||||
|
||||
-else.
|
||||
|
||||
|
@ -1570,9 +1570,7 @@ user_info(User, Server, Query, Lang) ->
|
||||
end,
|
||||
lists:sort(Resources))))]
|
||||
end,
|
||||
Password = ejabberd_auth:get_password_s(User, Server),
|
||||
FPassword = [?INPUT(<<"password">>, <<"password">>,
|
||||
Password),
|
||||
FPassword = [?INPUT(<<"text">>, <<"password">>, <<"">>),
|
||||
?C(<<" ">>),
|
||||
?INPUTT(<<"submit">>, <<"chpassword">>,
|
||||
<<"Change Password">>)],
|
||||
|
@ -345,8 +345,10 @@ build_fault_response(Code, ParseString, ParseArgs) ->
|
||||
do_command(AccessCommands, Auth, Command, AttrL, ArgsF,
|
||||
ResultF) ->
|
||||
ArgsFormatted = format_args(AttrL, ArgsF),
|
||||
{UserT, ServerT, PasswordT} = Auth,
|
||||
AuthBin = {list_to_binary(UserT), list_to_binary(ServerT), list_to_binary(PasswordT)},
|
||||
Result =
|
||||
ejabberd_commands:execute_command(AccessCommands, Auth,
|
||||
ejabberd_commands:execute_command(AccessCommands, AuthBin,
|
||||
Command, ArgsFormatted),
|
||||
ResultFormatted = format_result(Result, ResultF),
|
||||
{command_result, ResultFormatted}.
|
||||
|
@ -149,7 +149,7 @@ check_and_forward(JID, #xmlel{name = <<"message">>, attrs = Attrs} = Packet, Dir
|
||||
<<"chat">> ->
|
||||
case xml:get_subtag(Packet, <<"private">>) of
|
||||
false ->
|
||||
case xml:get_subtag(Packet,<<"forwarded">>) of
|
||||
case xml:get_subtag(Packet,<<"received">>) of
|
||||
false ->
|
||||
send_copies(JID, Packet, Direction);
|
||||
_ ->
|
||||
|
@ -657,7 +657,7 @@ load_permanent_rooms(Host, ServerHost, Access, HistorySize, RoomShaper) ->
|
||||
start_new_room(Host, ServerHost, Access, Room,
|
||||
HistorySize, RoomShaper, From,
|
||||
Nick, DefRoomOpts) ->
|
||||
case restore_room(ServerHost, Room, Host) of
|
||||
case restore_room(ServerHost, Host, Room) of
|
||||
error ->
|
||||
?DEBUG("MUC: open new room '~s'~n", [Room]),
|
||||
mod_muc_room:start(Host, ServerHost, Access,
|
||||
|
@ -2334,6 +2334,14 @@ send_nick_changing(JID, OldNick, StateData,
|
||||
[{<<"affiliation">>, SAffiliation},
|
||||
{<<"role">>, SRole}]
|
||||
end,
|
||||
Status110 = case JID == Info#user.jid of
|
||||
true ->
|
||||
[#xmlel{name = <<"status">>,
|
||||
attrs = [{<<"code">>, <<"110">>}]
|
||||
}];
|
||||
false ->
|
||||
[]
|
||||
end,
|
||||
Packet1 = #xmlel{name = <<"presence">>,
|
||||
attrs =
|
||||
[{<<"type">>,
|
||||
@ -2356,7 +2364,7 @@ send_nick_changing(JID, OldNick, StateData,
|
||||
[{<<"code">>,
|
||||
<<"303">>}],
|
||||
children =
|
||||
[]}]}]},
|
||||
[]}|Status110]}]},
|
||||
Packet2 = xml:append_subtags(Presence,
|
||||
[#xmlel{name = <<"x">>,
|
||||
attrs =
|
||||
@ -2371,7 +2379,7 @@ send_nick_changing(JID, OldNick, StateData,
|
||||
ItemAttrs2,
|
||||
children
|
||||
=
|
||||
[]}]}]),
|
||||
[]}|Status110]}]),
|
||||
if SendOldUnavailable ->
|
||||
ejabberd_router:route(jlib:jid_replace_resource(StateData#state.jid,
|
||||
OldNick),
|
||||
|
@ -130,6 +130,9 @@ stop(Host) ->
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host,
|
||||
?NS_ROSTER).
|
||||
|
||||
process_iq(From, To, IQ) when ((From#jid.luser == <<"">>) andalso (From#jid.resource == <<"">>)) ->
|
||||
process_iq_manager(From, To, IQ);
|
||||
|
||||
process_iq(From, To, IQ) ->
|
||||
#iq{sub_el = SubEl} = IQ,
|
||||
#jid{lserver = LServer} = From,
|
||||
@ -465,15 +468,16 @@ try_process_iq_set(From, To, #iq{sub_el = SubEl} = IQ) ->
|
||||
process_iq_set(From, To, IQ)
|
||||
end.
|
||||
|
||||
process_iq_set(From, To, #iq{sub_el = SubEl} = IQ) ->
|
||||
process_iq_set(From, To, #iq{sub_el = SubEl, id = Id} = IQ) ->
|
||||
#xmlel{children = Els} = SubEl,
|
||||
lists:foreach(fun (El) -> process_item_set(From, To, El)
|
||||
Managed = is_managed_from_id(Id),
|
||||
lists:foreach(fun (El) -> process_item_set(From, To, El, Managed)
|
||||
end,
|
||||
Els),
|
||||
IQ#iq{type = result, sub_el = []}.
|
||||
|
||||
process_item_set(From, To,
|
||||
#xmlel{attrs = Attrs, children = Els}) ->
|
||||
#xmlel{attrs = Attrs, children = Els}, Managed) ->
|
||||
JID1 = jlib:string_to_jid(xml:get_attr_s(<<"jid">>,
|
||||
Attrs)),
|
||||
#jid{user = User, luser = LUser, lserver = LServer} =
|
||||
@ -484,12 +488,13 @@ process_item_set(From, To,
|
||||
LJID = jlib:jid_tolower(JID1),
|
||||
F = fun () ->
|
||||
Item = get_roster_by_jid_t(LUser, LServer, LJID),
|
||||
Item1 = process_item_attrs(Item, Attrs),
|
||||
Item1 = process_item_attrs_managed(Item, Attrs, Managed),
|
||||
Item2 = process_item_els(Item1, Els),
|
||||
case Item2#roster.subscription of
|
||||
remove -> del_roster_t(LUser, LServer, LJID);
|
||||
_ -> update_roster_t(LUser, LServer, LJID, Item2)
|
||||
end,
|
||||
send_itemset_to_managers(From, Item2, Managed),
|
||||
Item3 = ejabberd_hooks:run_fold(roster_process_item,
|
||||
LServer, Item2,
|
||||
[LServer]),
|
||||
@ -511,7 +516,7 @@ process_item_set(From, To,
|
||||
?DEBUG("ROSTER: roster item set error: ~p~n", [E]), ok
|
||||
end
|
||||
end;
|
||||
process_item_set(_From, _To, _) -> ok.
|
||||
process_item_set(_From, _To, _, _Managed) -> ok.
|
||||
|
||||
process_item_attrs(Item, [{Attr, Val} | Attrs]) ->
|
||||
case Attr of
|
||||
@ -1554,6 +1559,91 @@ webadmin_user(Acc, _User, _Server, Lang) ->
|
||||
Acc ++
|
||||
[?XE(<<"h3">>, [?ACT(<<"roster/">>, <<"Roster">>)])].
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
%% Implement XEP-0321 Remote Roster Management
|
||||
|
||||
process_iq_manager(From, To, IQ) ->
|
||||
%% Check what access is allowed for From to To
|
||||
MatchDomain = From#jid.lserver,
|
||||
case is_domain_managed(MatchDomain, To#jid.lserver) of
|
||||
true ->
|
||||
process_iq_manager2(MatchDomain, To, IQ);
|
||||
false ->
|
||||
#iq{sub_el = SubEl} = IQ,
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]}
|
||||
end.
|
||||
|
||||
process_iq_manager2(MatchDomain, To, IQ) ->
|
||||
%% If IQ is SET, filter the input IQ
|
||||
IQFiltered = maybe_filter_request(MatchDomain, IQ),
|
||||
%% Call the standard function with reversed JIDs
|
||||
IdInitial = IQFiltered#iq.id,
|
||||
ResIQ = process_iq(To, To, IQFiltered#iq{id = <<"roster-remotely-managed">>}),
|
||||
%% Filter the output IQ
|
||||
filter_stanza(MatchDomain, ResIQ#iq{id = IdInitial}).
|
||||
|
||||
is_domain_managed(ContactHost, UserHost) ->
|
||||
Managers = gen_mod:get_module_opt(UserHost, ?MODULE, managers,
|
||||
fun(B) when is_list(B) -> B end,
|
||||
[]),
|
||||
lists:member(ContactHost, Managers).
|
||||
|
||||
maybe_filter_request(MatchDomain, IQ) when IQ#iq.type == set ->
|
||||
filter_stanza(MatchDomain, IQ);
|
||||
maybe_filter_request(_MatchDomain, IQ) ->
|
||||
IQ.
|
||||
|
||||
filter_stanza(_MatchDomain, #iq{sub_el = []} = IQ) ->
|
||||
IQ;
|
||||
filter_stanza(MatchDomain, #iq{sub_el = [SubEl | _]} = IQ) ->
|
||||
#iq{sub_el = SubElFiltered} = IQRes =
|
||||
filter_stanza(MatchDomain, IQ#iq{sub_el = SubEl}),
|
||||
IQRes#iq{sub_el = [SubElFiltered]};
|
||||
filter_stanza(MatchDomain, #iq{sub_el = SubEl} = IQ) ->
|
||||
#xmlel{name = Type, attrs = Attrs, children = Items} = SubEl,
|
||||
ItemsFiltered = lists:filter(
|
||||
fun(Item) ->
|
||||
is_item_of_domain(MatchDomain, Item) end, Items),
|
||||
SubElFiltered = #xmlel{name=Type, attrs = Attrs, children = ItemsFiltered},
|
||||
IQ#iq{sub_el = SubElFiltered}.
|
||||
|
||||
is_item_of_domain(MatchDomain, #xmlel{} = El) ->
|
||||
lists:any(fun(Attr) -> is_jid_of_domain(MatchDomain, Attr) end, El#xmlel.attrs);
|
||||
is_item_of_domain(_MatchDomain, {xmlcdata, _}) ->
|
||||
false.
|
||||
|
||||
is_jid_of_domain(MatchDomain, {<<"jid">>, JIDString}) ->
|
||||
case jlib:string_to_jid(JIDString) of
|
||||
JID when JID#jid.lserver == MatchDomain -> true;
|
||||
_ -> false
|
||||
end;
|
||||
is_jid_of_domain(_, _) ->
|
||||
false.
|
||||
|
||||
process_item_attrs_managed(Item, Attrs, true) ->
|
||||
process_item_attrs_ws(Item, Attrs);
|
||||
process_item_attrs_managed(Item, _Attrs, false) ->
|
||||
process_item_attrs(Item, _Attrs).
|
||||
|
||||
send_itemset_to_managers(_From, _Item, true) ->
|
||||
ok;
|
||||
send_itemset_to_managers(From, Item, false) ->
|
||||
{_, UserHost} = Item#roster.us,
|
||||
{_ContactUser, ContactHost, _ContactResource} = Item#roster.jid,
|
||||
%% Check if the component is an allowed manager
|
||||
IsManager = is_domain_managed(ContactHost, UserHost),
|
||||
case IsManager of
|
||||
true -> push_item(<<"">>, ContactHost, <<"">>, From, Item);
|
||||
false -> ok
|
||||
end.
|
||||
|
||||
is_managed_from_id(<<"roster-remotely-managed">>) ->
|
||||
true;
|
||||
is_managed_from_id(_Id) ->
|
||||
false.
|
||||
|
||||
|
||||
export(_Server) ->
|
||||
[{roster,
|
||||
fun(Host, #roster{usj = {LUser, LServer, LJID}} = R)
|
||||
|
Loading…
Reference in New Issue
Block a user