diff --git a/src/ejabberd_xmlrpc.erl b/src/ejabberd_xmlrpc.erl index 6680451e4..6259b4efd 100644 --- a/src/ejabberd_xmlrpc.erl +++ b/src/ejabberd_xmlrpc.erl @@ -42,7 +42,7 @@ -include("ejabberd_http.hrl"). -include("mod_roster.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -record(state, {access_commands = [] :: list(), diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl index 8f6724281..a147a5881 100644 --- a/src/mod_admin_extra.erl +++ b/src/mod_admin_extra.erl @@ -54,7 +54,7 @@ -include("ejabberd_commands.hrl"). -include("mod_roster.hrl"). -include("ejabberd_sm.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). %%% %%% gen_mod @@ -879,20 +879,22 @@ set_presence(User, Host, Resource, Type, Show, Status, Priority) when is_integer(Priority) -> BPriority = integer_to_binary(Priority), set_presence(User, Host, Resource, Type, Show, Status, BPriority); -set_presence(User, Host, Resource, Type, Show, Status, Priority) -> +set_presence(User, Host, Resource, Type, Show, Status, Priority0) -> + Priority = if is_integer(Priority0) -> Priority0; + true -> binary_to_integer(Priority0) + end, case ejabberd_sm:get_session_pid(User, Host, Resource) of none -> error; Pid -> - USR = jid:to_string(jid:make(User, Host, Resource)), - US = jid:to_string(jid:make(User, Host, <<>>)), - Message = {route_xmlstreamelement, - {xmlel, <<"presence">>, - [{<<"from">>, USR}, {<<"to">>, US}, {<<"type">>, Type}], - [{xmlel, <<"show">>, [], [{xmlcdata, Show}]}, - {xmlel, <<"status">>, [], [{xmlcdata, Status}]}, - {xmlel, <<"priority">>, [], [{xmlcdata, Priority}]}]}}, - Pid ! Message, + From = jid:make(User, Host, Resource), + To = jid:make(User, Host), + Presence = #presence{from = From, to = To, + type = jlib:binary_to_atom(Type), + show = jlib:binary_to_atom(Show), + status = xmpp:mk_text(Status), + priority = Priority}, + Pid ! {route, From, To, Presence}, ok end. @@ -930,20 +932,12 @@ user_sessions_info(User, Host) -> %%% set_nickname(User, Host, Nickname) -> - R = mod_vcard:process_sm_iq( - {jid, User, Host, <<>>, User, Host, <<>>}, - {jid, User, Host, <<>>, User, Host, <<>>}, - {iq, <<>>, set, <<>>, <<"en">>, - {xmlel, <<"vCard">>, [ - {<<"xmlns">>, <<"vcard-temp">>}], [ - {xmlel, <<"NICKNAME">>, [], [{xmlcdata, Nickname}]} - ] - }}), - case R of - {iq, <<>>, result, <<>>, _L, []} -> - ok; - _ -> - error + VCard = xmpp:encode(#vcard_temp{nickname = Nickname}), + case mod_vcard:set_vcard(User, jid:nameprep(Host), VCard) of + {error, badarg} -> + error; + ok -> + ok end. get_vcard(User, Host, Name) -> @@ -967,26 +961,17 @@ set_vcard(User, Host, Name, Subname, SomeContent) -> %% %% Internal vcard -get_module_resource(Server) -> - case gen_mod:get_module_opt(Server, ?MODULE, module_resource, fun(A) -> A end, none) of - none -> list_to_binary(atom_to_list(?MODULE)); - R when is_binary(R) -> R - end. - get_vcard_content(User, Server, Data) -> - [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}), - JID = jid:make(User, Server, get_module_resource(Server)), - IQ = #iq{type = get, xmlns = ?NS_VCARD}, - IQr = Module:Function(JID, JID, IQ), - [A1] = IQr#iq.sub_el, - case A1#xmlel.children of - [_|_] -> - case get_vcard(Data, A1) of + case mod_vcard:get_vcard(jid:nodeprep(User), jid:nameprep(Server)) of + [_|_] = Els -> + case get_vcard(Data, Els) of [false] -> throw(error_no_value_found_in_vcard); ElemList -> ?DEBUG("ELS ~p", [ElemList]), [fxml:get_tag_cdata(Elem) || Elem <- ElemList] end; [] -> - throw(error_no_vcard_found) + throw(error_no_vcard_found); + error -> + throw(database_failure) end. get_vcard([<<"TEL">>, TelType], {_, _, _, OldEls}) -> @@ -1011,25 +996,19 @@ set_vcard_content(User, Server, Data, SomeContent) -> [Bin | _] when is_binary(Bin) -> SomeContent; Bin when is_binary(Bin) -> [SomeContent] end, - [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}), - JID = jid:make(User, Server, get_module_resource(Server)), - IQ = #iq{type = get, xmlns = ?NS_VCARD}, - IQr = Module:Function(JID, JID, IQ), - %% Get old vcard - A4 = case IQr#iq.sub_el of + A4 = case mod_vcard:get_vcard(jid:nodeprep(User), jid:nameprep(Server)) of [A1] -> {_, _, _, A2} = A1, update_vcard_els(Data, ContentList, A2); [] -> - update_vcard_els(Data, ContentList, []) + update_vcard_els(Data, ContentList, []); + error -> + throw(database_failure) end, - %% Build new vcard SubEl = {xmlel, <<"vCard">>, [{<<"xmlns">>,<<"vcard-temp">>}], A4}, - IQ2 = #iq{type=set, sub_el = SubEl}, - - Module:Function(JID, JID, IQ2), + mod_vcard:set_vcard(User, jid:nameprep(Server), SubEl), ok. take_vcard_tel(TelType, [{xmlel, <<"TEL">>, _, SubEls}=OldEl | OldEls], NewEls, Taken) -> @@ -1090,11 +1069,7 @@ add_rosteritem(LU, LS, User, Server, Nick, Group, Subscription, Xattrs) -> subscribe(LU, LS, User, Server, Nick, Group, Subscription, _Xattrs) -> ItemEl = build_roster_item(User, Server, {add, Nick, Subscription, Group}), - mod_roster:set_items( - LU, LS, - {xmlel, <<"query">>, - [{<<"xmlns">>, ?NS_ROSTER}], - [ItemEl]}). + mod_roster:set_items(LU, LS, #roster_query{items = [ItemEl]}). delete_rosteritem(LocalUser, LocalServer, User, Server) -> case unsubscribe(LocalUser, LocalServer, User, Server) of @@ -1107,11 +1082,7 @@ delete_rosteritem(LocalUser, LocalServer, User, Server) -> unsubscribe(LU, LS, User, Server) -> ItemEl = build_roster_item(User, Server, remove), - mod_roster:set_items( - LU, LS, - {xmlel, <<"query">>, - [{<<"xmlns">>, ?NS_ROSTER}], - [ItemEl]}). + mod_roster:set_items(LU, LS, #roster_query{items = [ItemEl]}). %% ----------------------------- %% Get Roster @@ -1201,28 +1172,16 @@ push_roster_item(LU, LS, R, U, S, Action) -> ejabberd_router:route(jid:remove_resource(LJID), LJID, ResIQ). build_roster_item(U, S, {add, Nick, Subs, Group}) -> - {xmlel, <<"item">>, - [{<<"jid">>, jid:to_string(jid:make(U, S, <<>>))}, - {<<"name">>, Nick}, - {<<"subscription">>, Subs}], - [{xmlel, <<"group">>, [], [{xmlcdata, Group}]}] - }; + #roster_item{jid = jid:make(U, S), + name = Nick, + subscription = jlib:binary_to_atom(Subs), + groups = [Group]}; build_roster_item(U, S, remove) -> - {xmlel, <<"item">>, - [{<<"jid">>, jid:to_string(jid:make(U, S, <<>>))}, - {<<"subscription">>, <<"remove">>}], - [] - }. + #roster_item{jid = jid:make(U, S), subscription = remove}. build_iq_roster_push(Item) -> - {xmlel, <<"iq">>, - [{<<"type">>, <<"set">>}, {<<"id">>, <<"push">>}], - [{xmlel, <<"query">>, - [{<<"xmlns">>, ?NS_ROSTER}], - [Item] - } - ] - }. + #iq{type = set, id = <<"push">>, + sub_els = [#roster_query{items = [Item]}]}. build_broadcast(U, S, {add, _Nick, Subs, _Group}) -> build_broadcast(U, S, list_to_atom(binary_to_list(Subs))); @@ -1268,17 +1227,9 @@ get_last(User, Server) -> %% Cluth private_get(Username, Host, Element, Ns) -> - From = jid:make(Username, Host, <<>>), - To = jid:make(Username, Host, <<>>), - IQ = {iq, <<>>, get, ?NS_PRIVATE, <<>>, - {xmlel, <<"query">>, - [{<<"xmlns">>,?NS_PRIVATE}], - [{xmlel, Element, [{<<"xmlns">>, Ns}], []}]}}, - ResIq = mod_private:process_sm_iq(From, To, IQ), - [{xmlel, <<"query">>, - [{<<"xmlns">>, ?NS_PRIVATE}], - [SubEl]}] = ResIq#iq.sub_el, - binary_to_list(fxml:element_to_binary(SubEl)). + Els = mod_private:get_data(jid:nodeprep(Username), jid:nameprep(Host), + [Ns, Element]), + binary_to_list(fxml:element_to_binary(xmpp:encode(#private{xml_els = Els}))). private_set(Username, Host, ElementString) -> case fxml_stream:parse_element(ElementString) of @@ -1291,13 +1242,9 @@ private_set(Username, Host, ElementString) -> end. private_set2(Username, Host, Xml) -> - From = jid:make(Username, Host, <<>>), - To = jid:make(Username, Host, <<>>), - IQ = {iq, <<>>, set, ?NS_PRIVATE, <<>>, - {xmlel, <<"query">>, - [{<<"xmlns">>, ?NS_PRIVATE}], - [Xml]}}, - mod_private:process_sm_iq(From, To, IQ), + NS = fxml:get_tag_attr_s(<<"xmlns">>, Xml), + mod_private:set_data(jid:nodeprep(Username), jid:nameprep(Host), + [{NS, Xml}]), ok. %%% @@ -1395,23 +1342,25 @@ send_packet_all_resources(FromJID, ToU, ToS, ToR, Packet) -> ejabberd_router:route(FromJID, ToJID, Packet). build_packet(Type, Subject, Body) -> - Tail = if Subject == <<"">>; Type == <<"chat">> -> []; - true -> [{xmlel, <<"subject">>, [], [{xmlcdata, Subject}]}] - end, - {xmlel, <<"message">>, - [{<<"type">>, Type}, {<<"id">>, randoms:get_string()}], - [{xmlel, <<"body">>, [], [{xmlcdata, Body}]} | Tail] - }. + #message{type = jlib:binary_to_atom(Type), + body = xmpp:mk_text(Body), + subject = xmpp:mk_text(Subject)}. send_stanza(FromString, ToString, Stanza) -> - case fxml_stream:parse_element(Stanza) of - {error, Error} -> - {error, Error}; - XmlEl -> - #xmlel{attrs = Attrs} = XmlEl, - From = jid:from_string(proplists:get_value(<<"from">>, Attrs, FromString)), - To = jid:from_string(proplists:get_value(<<"to">>, Attrs, ToString)), - ejabberd_router:route(From, To, XmlEl) + try + #xmlel{} = El = fxml_stream:parse_element(Stanza), + #jid{} = From = jid:from_string(FromString), + #jid{} = To = jid:to_string(ToString), + Pkt = xmpp:decode(El, [ignore_els]), + ejabberd_router:route(From, To, Pkt) + catch _:{xmpp_codec, Why} -> + io:format("incorrect stanza: ~s~n", [xmpp:format_error(Why)]), + {error, Why}; + _:{badmatch, {error, Why}} -> + io:format("invalid xml: ~p~n", [Why]), + {error, Why}; + _:{badmatch, error} -> + {error, "JID malformed"} end. send_stanza_c2s(Username, Host, Resource, Stanza) -> @@ -1427,17 +1376,15 @@ send_stanza_c2s(Username, Host, Resource, Stanza) -> end. privacy_set(Username, Host, QueryS) -> - From = jid:make(Username, Host, <<"">>), - To = jid:make(<<"">>, Host, <<"">>), + From = jid:make(Username, Host), + To = jid:make(Host), QueryEl = fxml_stream:parse_element(QueryS), - StanzaEl = {xmlel, <<"iq">>, [{<<"type">>, <<"set">>}], [QueryEl]}, - IQ = jlib:iq_query_info(StanzaEl), - ejabberd_hooks:run_fold( - privacy_iq_set, - Host, - {error, ?ERR_FEATURE_NOT_IMPLEMENTED}, - [From, To, IQ] - ), + SubEl = xmpp:decode(QueryEl), + IQ = #iq{type = set, id = <<"push">>, sub_els = [SubEl]}, + ejabberd_hooks:run_fold(privacy_iq_set, + Host, + {error, xmpp:err_feature_not_implemented()}, + [From, To, IQ]), ok. %%% @@ -1618,5 +1565,4 @@ is_glob_match(String, <<"!", Glob/binary>>) -> is_glob_match(String, Glob) -> is_regexp_match(String, ejabberd_regexp:sh_to_awk(Glob)). -mod_opt_type(module_resource) -> fun (A) -> A end; -mod_opt_type(_) -> [module_resource]. +mod_opt_type(_) -> []. diff --git a/src/mod_http_api.erl b/src/mod_http_api.erl index 815ed3ab6..f3a69aa80 100644 --- a/src/mod_http_api.erl +++ b/src/mod_http_api.erl @@ -77,7 +77,7 @@ -export([start/2, stop/1, process/2, mod_opt_type/1, depends/2]). -include("ejabberd.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -include("logger.hrl"). -include("ejabberd_http.hrl"). diff --git a/src/mod_http_fileserver.erl b/src/mod_http_fileserver.erl index 37e02edd8..728a2d137 100644 --- a/src/mod_http_fileserver.erl +++ b/src/mod_http_fileserver.erl @@ -51,9 +51,6 @@ -include("ejabberd.hrl"). -include("logger.hrl"). -include("ejabberd_http.hrl"). - --include("jlib.hrl"). - -include_lib("kernel/include/file.hrl"). -record(state, diff --git a/src/mod_metrics.erl b/src/mod_metrics.erl index f1d487e0e..cb7946a28 100644 --- a/src/mod_metrics.erl +++ b/src/mod_metrics.erl @@ -31,7 +31,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("jid.hrl"). -define(HOOKS, [offline_message_hook, sm_register_connection_hook, sm_remove_connection_hook, diff --git a/src/mod_pres_counter.erl b/src/mod_pres_counter.erl index e6f2cfbab..786ba97f2 100644 --- a/src/mod_pres_counter.erl +++ b/src/mod_pres_counter.erl @@ -33,7 +33,7 @@ -include("ejabberd.hrl"). -include("logger.hrl"). --include("jlib.hrl"). +-include("xmpp.hrl"). -record(pres_counter, {dir, start, count, logged = false}). @@ -52,27 +52,24 @@ depends(_Host, _Opts) -> []. check_packet(_, _User, Server, _PrivacyList, - {From, To, #xmlel{name = Name, attrs = Attrs}}, Dir) -> - case Name of - <<"presence">> -> - IsSubscription = case fxml:get_attr_s(<<"type">>, Attrs) - of - <<"subscribe">> -> true; - <<"subscribed">> -> true; - <<"unsubscribe">> -> true; - <<"unsubscribed">> -> true; - _ -> false - end, - if IsSubscription -> - JID = case Dir of - in -> To; - out -> From - end, - update(Server, JID, Dir); - true -> allow - end; - _ -> allow - end. + {From, To, #presence{type = Type}}, Dir) -> + IsSubscription = case Type of + subscribe -> true; + subscribed -> true; + unsubscribe -> true; + unsubscribed -> true; + _ -> false + end, + if IsSubscription -> + JID = case Dir of + in -> To; + out -> From + end, + update(Server, JID, Dir); + true -> allow + end; +check_packet(_, _User, _Server, _PrivacyList, _Pkt, _Dir) -> + allow. update(Server, JID, Dir) -> StormCount = gen_mod:get_module_opt(Server, ?MODULE, count, diff --git a/src/mod_private.erl b/src/mod_private.erl index e6d0fd7cd..6236b1012 100644 --- a/src/mod_private.erl +++ b/src/mod_private.erl @@ -32,7 +32,7 @@ -behaviour(gen_mod). -export([start/2, stop/1, process_sm_iq/1, import/3, - remove_user/2, get_data/2, export/1, import/1, + remove_user/2, get_data/2, get_data/3, export/1, import/1, mod_opt_type/1, set_data/3, depends/2]). -include("ejabberd.hrl"). diff --git a/src/mod_proxy65_service.erl b/src/mod_proxy65_service.erl index 7db6f9da2..e90ff21bd 100644 --- a/src/mod_proxy65_service.erl +++ b/src/mod_proxy65_service.erl @@ -33,24 +33,17 @@ -export([init/1, handle_info/2, handle_call/3, handle_cast/2, terminate/2, code_change/3]). --export([start_link/2, add_listener/2, +-export([start_link/2, add_listener/2, process_disco_info/1, + process_disco_items/1, process_vcard/1, process_bytestreams/1, transform_module_options/1, delete_listener/1]). -include("ejabberd.hrl"). -include("logger.hrl"). - --include("jlib.hrl"). +-include("xmpp.hrl"). -define(PROCNAME, ejabberd_mod_proxy65_service). --record(state, - {myhost = <<"">> :: binary(), - serverhost = <<"">> :: binary(), - name = <<"">> :: binary(), - stream_addr = [] :: [attr()], - port = 0 :: inet:port_number(), - ip = {127,0,0,1} :: inet:ip_address(), - acl = none :: atom()}). +-record(state, {myhost = <<"">> :: binary()}). %%%------------------------ %%% gen_server callbacks @@ -62,34 +55,32 @@ start_link(Host, Opts) -> [Host, Opts], []). init([Host, Opts]) -> - State = parse_options(Host, Opts), - ejabberd_router:register_route(State#state.myhost, Host), - {ok, State}. + IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1, + one_queue), + MyHost = gen_mod:get_opt_host(Host, Opts, <<"proxy.@HOST@">>), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_INFO, + ?MODULE, process_disco_info, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_ITEMS, + ?MODULE, process_disco_items, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_VCARD, + ?MODULE, process_vcard, IQDisc), + gen_iq_handler:add_iq_handler(ejabberd_local, MyHost, ?NS_BYTESTREAMS, + ?MODULE, process_bytestreams, IQDisc), + ejabberd_router:register_route(MyHost, Host), + {ok, #state{myhost = MyHost}}. terminate(_Reason, #state{myhost = MyHost}) -> - ejabberd_router:unregister_route(MyHost), ok. + ejabberd_router:unregister_route(MyHost), + gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_INFO), + gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_DISCO_ITEMS), + gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_VCARD), + gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_BYTESTREAMS). -handle_info({route, From, To, - #xmlel{name = <<"iq">>} = Packet}, - State) -> - IQ = jlib:iq_query_info(Packet), - case catch process_iq(From, IQ, State) of - Result when is_record(Result, iq) -> - ejabberd_router:route(To, From, jlib:iq_to_xml(Result)); - {'EXIT', Reason} -> - ?ERROR_MSG("Error when processing IQ stanza: ~p", - [Reason]), - Err = jlib:make_error_reply(Packet, - ?ERR_INTERNAL_SERVER_ERROR), - ejabberd_router:route(To, From, Err); - _ -> ok - end, +handle_info({route, From, To, #iq{} = Packet}, State) -> + ejabberd_router:process_iq(From, To, Packet), {noreply, State}; handle_info(_Info, State) -> {noreply, State}. -handle_call(get_port_ip, _From, State) -> - {reply, {port_ip, State#state.port, State#state.ip}, - State}; handle_call(_Request, _From, State) -> {reply, ok, State}. @@ -102,185 +93,122 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}. %%%------------------------ add_listener(Host, Opts) -> - State = parse_options(Host, Opts), NewOpts = [Host | Opts], - ejabberd_listener:add_listener({State#state.port, - State#state.ip}, + ejabberd_listener:add_listener(get_port_ip(Host), mod_proxy65_stream, NewOpts). delete_listener(Host) -> - Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - {port_ip, Port, IP} = gen_server:call(Proc, - get_port_ip), - catch ejabberd_listener:delete_listener({Port, IP}, + catch ejabberd_listener:delete_listener(get_port_ip(Host), mod_proxy65_stream). %%%------------------------ %%% IQ Processing %%%------------------------ +-spec process_disco_info(iq()) -> iq(). +process_disco_info(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_disco_info(#iq{type = get, to = To, lang = Lang} = IQ) -> + Host = ejabberd_router:host_of_route(To#jid.lserver), + Name = gen_mod:get_module_opt(Host, mod_proxy65, name, + fun iolist_to_binary/1, + <<"SOCKS5 Bytestreams">>), + Info = ejabberd_hooks:run_fold(disco_info, Host, + [], [Host, ?MODULE, <<"">>, <<"">>]), + xmpp:make_iq_result( + IQ, #disco_info{xdata = Info, + identities = [#identity{category = <<"proxy">>, + type = <<"bytestreams">>, + name = translate:translate(Lang, Name)}], + features = [?NS_DISCO_INFO, ?NS_DISCO_ITEMS, + ?NS_VCARD, ?NS_BYTESTREAMS]}). -%% disco#info request -process_iq(_, - #iq{type = get, xmlns = ?NS_DISCO_INFO, lang = Lang} = - IQ, - #state{name = Name, serverhost = ServerHost}) -> - Info = ejabberd_hooks:run_fold(disco_info, ServerHost, - [], [ServerHost, ?MODULE, <<"">>, <<"">>]), - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_DISCO_INFO}], - children = iq_disco_info(Lang, Name) ++ Info}]}; -%% disco#items request -process_iq(_, - #iq{type = get, xmlns = ?NS_DISCO_ITEMS} = IQ, _) -> - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_DISCO_ITEMS}], - children = []}]}; -%% vCard request -process_iq(_, - #iq{type = get, xmlns = ?NS_VCARD, lang = Lang} = IQ, - _) -> - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"vCard">>, - attrs = [{<<"xmlns">>, ?NS_VCARD}], - children = iq_vcard(Lang)}]}; -%% bytestreams info request -process_iq(JID, - #iq{type = get, sub_el = SubEl, lang = Lang, - xmlns = ?NS_BYTESTREAMS} = - IQ, - #state{acl = ACL, stream_addr = StreamAddr, - serverhost = ServerHost}) -> +-spec process_disco_items(iq()) -> iq(). +process_disco_items(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_disco_items(#iq{type = get} = IQ) -> + xmpp:make_iq_result(IQ, #disco_items{}). + +-spec process_vcard(iq()) -> iq(). +process_vcard(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_vcard(#iq{type = get, lang = Lang} = IQ) -> + Desc = translate:translate(Lang, <<"ejabberd SOCKS5 Bytestreams module">>), + Copyright = <<"Copyright (c) 2003-2016 ProcessOne">>, + xmpp:make_iq_result( + IQ, #vcard_temp{fn = <<"ejabberd/mod_proxy65">>, + url = ?EJABBERD_URI, + desc = <>}). + +-spec process_bytestreams(iq()) -> iq(). +process_bytestreams(#iq{type = get, from = JID, to = To, lang = Lang} = IQ) -> + Host = To#jid.lserver, + ServerHost = ejabberd_router:host_of_route(Host), + ACL = gen_mod:get_module_opt(ServerHost, mod_proxy65, access, + fun acl:access_rules_validator/1, + all), case acl:match_rule(ServerHost, ACL, JID) of - allow -> - StreamHostEl = [#xmlel{name = <<"streamhost">>, - attrs = StreamAddr, children = []}], - IQ#iq{type = result, - sub_el = - [#xmlel{name = <<"query">>, - attrs = [{<<"xmlns">>, ?NS_BYTESTREAMS}], - children = StreamHostEl}]}; - deny -> - Txt = <<"Denied by ACL">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_FORBIDDEN(Lang, Txt)]} + allow -> + StreamHost = get_streamhost(Host, ServerHost), + xmpp:make_iq_result(IQ, #bytestreams{hosts = [StreamHost]}); + deny -> + xmpp:make_error(IQ, xmpp:err_forbidden(<<"Denied by ACL">>, Lang)) end; -%% bytestream activation request -process_iq(InitiatorJID, - #iq{type = set, sub_el = SubEl, lang = Lang, - xmlns = ?NS_BYTESTREAMS} = - IQ, - #state{acl = ACL, serverhost = ServerHost}) -> +process_bytestreams(#iq{type = set, lang = Lang, + sub_els = [#bytestreams{sid = undefined}]} = IQ) -> + Why = {missing_attr, <<"sid">>, <<"query">>, ?NS_BYTESTREAMS}, + Txt = xmpp:format_error(Why), + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)); +process_bytestreams(#iq{type = set, lang = Lang, + sub_els = [#bytestreams{sid = SID}]} = IQ) + when SID == <<"">> orelse length(SID) > 128 -> + Why = {bad_attr_value, <<"sid">>, <<"query">>, ?NS_BYTESTREAMS}, + Txt = xmpp:format_error(Why), + xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)); +process_bytestreams(#iq{type = set, lang = Lang, + sub_els = [#bytestreams{activate = undefined}]} = IQ) -> + Why = {missing_cdata, <<"">>, <<"activate">>, ?NS_BYTESTREAMS}, + Txt = xmpp:format_error(Why), + xmpp:make_error(IQ, xmpp:err_jid_malformed(Txt, Lang)); +process_bytestreams(#iq{type = set, lang = Lang, from = InitiatorJID, to = To, + sub_els = [#bytestreams{activate = TargetJID, + sid = SID}]} = IQ) -> + ServerHost = ejabberd_router:host_of_route(To#jid.lserver), + ACL = gen_mod:get_module_opt(ServerHost, mod_proxy65, access, + fun acl:access_rules_validator/1, + all), case acl:match_rule(ServerHost, ACL, InitiatorJID) of - allow -> - ActivateEl = fxml:get_path_s(SubEl, - [{elem, <<"activate">>}]), - SID = fxml:get_tag_attr_s(<<"sid">>, SubEl), - case catch - jid:from_string(fxml:get_tag_cdata(ActivateEl)) - of - TargetJID - when is_record(TargetJID, jid), SID /= <<"">>, - byte_size(SID) =< 128, TargetJID /= InitiatorJID -> - Target = - jid:to_string(jid:tolower(TargetJID)), - Initiator = - jid:to_string(jid:tolower(InitiatorJID)), - SHA1 = p1_sha:sha(<>), - case mod_proxy65_sm:activate_stream(SHA1, InitiatorJID, - TargetJID, ServerHost) - of - ok -> IQ#iq{type = result, sub_el = []}; - false -> - Txt = <<"Failed to activate bytestream">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)]}; - limit -> - Txt = <<"Too many active bytestreams">>, - IQ#iq{type = error, - sub_el = [SubEl, ?ERRT_RESOURCE_CONSTRAINT(Lang, Txt)]}; - conflict -> - Txt = <<"Bytestream already activated">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_CONFLICT(Lang, Txt)]}; - _ -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} - end; - _ -> - Txt = <<"Malformed JID">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]} - end; - deny -> - Txt = <<"Denied by ACL">>, - IQ#iq{type = error, sub_el = [SubEl, ?ERRT_FORBIDDEN(Lang, Txt)]} - end; -%% Unknown "set" or "get" request -process_iq(_, #iq{type = Type, sub_el = SubEl} = IQ, _) - when Type == get; Type == set -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]}; -%% IQ "result" or "error". -process_iq(_, _, _) -> ok. - + allow -> + Target = jid:to_string(jid:tolower(TargetJID)), + Initiator = jid:to_string(jid:tolower(InitiatorJID)), + SHA1 = p1_sha:sha(<>), + case mod_proxy65_sm:activate_stream(SHA1, InitiatorJID, + TargetJID, ServerHost) of + ok -> + xmpp:make_iq_result(IQ); + false -> + Txt = <<"Failed to activate bytestream">>, + xmpp:make_error(IQ, xmpp:err_item_not_found(Txt, Lang)); + limit -> + Txt = <<"Too many active bytestreams">>, + xmpp:make_error(IQ, xmpp:err_resource_constraint(Txt, Lang)); + conflict -> + Txt = <<"Bytestream already activated">>, + xmpp:make_error(IQ, xmpp:err_conflict(Txt, Lang)); + Err -> + ?ERROR_MSG("failed to activate bytestream from ~s to ~s: ~p", + [Initiator, Target, Err]), + xmpp:make_error(IQ, xmpp:err_internal_server_error()) + end; + deny -> + Txt = <<"Denied by ACL">>, + xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang)) + end. %%%------------------------- %%% Auxiliary functions. %%%------------------------- --define(FEATURE(Feat), - #xmlel{name = <<"feature">>, - attrs = [{<<"var">>, Feat}], children = []}). - -iq_disco_info(Lang, Name) -> - [#xmlel{name = <<"identity">>, - attrs = - [{<<"category">>, <<"proxy">>}, - {<<"type">>, <<"bytestreams">>}, - {<<"name">>, translate:translate(Lang, Name)}], - children = []}, - ?FEATURE((?NS_DISCO_INFO)), ?FEATURE((?NS_VCARD)), - ?FEATURE((?NS_BYTESTREAMS))]. - -iq_vcard(Lang) -> - [#xmlel{name = <<"FN">>, attrs = [], - children = [{xmlcdata, <<"ejabberd/mod_proxy65">>}]}, - #xmlel{name = <<"URL">>, attrs = [], - children = [{xmlcdata, ?EJABBERD_URI}]}, - #xmlel{name = <<"DESC">>, attrs = [], - children = - [{xmlcdata, - <<(translate:translate(Lang, - <<"ejabberd SOCKS5 Bytestreams module">>))/binary, - "\nCopyright (c) 2003-2016 ProcessOne">>}]}]. - -parse_options(ServerHost, Opts) -> - MyHost = gen_mod:get_opt_host(ServerHost, Opts, - <<"proxy.@HOST@">>), - Port = gen_mod:get_opt(port, Opts, - fun(P) when is_integer(P), P>0, P<65536 -> P end, - 7777), - ACL = gen_mod:get_opt(access, Opts, fun acl:access_rules_validator/1, - all), - Name = gen_mod:get_opt(name, Opts, fun iolist_to_binary/1, - <<"SOCKS5 Bytestreams">>), - IP = gen_mod:get_opt(ip, Opts, - fun(S) -> - {ok, Addr} = inet_parse:address( - binary_to_list( - iolist_to_binary(S))), - Addr - end, get_my_ip()), - HostName = gen_mod:get_opt(hostname, Opts, - fun iolist_to_binary/1, - jlib:ip_to_list(IP)), - StreamAddr = [{<<"jid">>, MyHost}, - {<<"host">>, HostName}, - {<<"port">>, jlib:integer_to_binary(Port)}], - #state{myhost = MyHost, serverhost = ServerHost, - name = Name, port = Port, ip = IP, - stream_addr = StreamAddr, acl = ACL}. - transform_module_options(Opts) -> lists:map( fun({ip, IP}) when is_tuple(IP) -> @@ -291,6 +219,33 @@ transform_module_options(Opts) -> Opt end, Opts). +-spec get_streamhost(binary(), binary()) -> streamhost(). +get_streamhost(Host, ServerHost) -> + {Port, IP} = get_port_ip(ServerHost), + HostName = gen_mod:get_module_opt(ServerHost, mod_proxy65, hostname, + fun iolist_to_binary/1, + jlib:ip_to_list(IP)), + #streamhost{jid = jid:make(Host), + host = HostName, + port = Port}. + +-spec get_port_ip(binary()) -> {pos_integer(), inet:ip_address()}. +get_port_ip(Host) -> + Port = gen_mod:get_module_opt(Host, mod_proxy65, port, + fun(P) when is_integer(P), P>0, P<65536 -> + P + end, + 7777), + IP = gen_mod:get_module_opt(Host, mod_proxy65, ip, + fun(S) -> + {ok, Addr} = inet_parse:address( + binary_to_list( + iolist_to_binary(S))), + Addr + end, get_my_ip()), + {Port, IP}. + +-spec get_my_ip() -> inet:ip_address(). get_my_ip() -> {ok, MyHostName} = inet:gethostname(), case inet:getaddr(MyHostName, inet) of diff --git a/src/mod_proxy65_sm.erl b/src/mod_proxy65_sm.erl index d86b06c4b..7ef4d390e 100644 --- a/src/mod_proxy65_sm.erl +++ b/src/mod_proxy65_sm.erl @@ -38,14 +38,12 @@ -record(state, {max_connections = infinity :: non_neg_integer() | infinity}). --include("jlib.hrl"). - -record(bytestream, {sha1 = <<"">> :: binary() | '$1', target :: pid() | '_', initiator :: pid() | '_', active = false :: boolean() | '_', - jid_i = {<<"">>, <<"">>, <<"">>} :: ljid() | '_'}). + jid_i = {<<"">>, <<"">>, <<"">>} :: jid:ljid() | '_'}). -define(PROCNAME, ejabberd_mod_proxy65_sm). diff --git a/src/mod_service_log.erl b/src/mod_service_log.erl index ae264bbc9..8f11b0ead 100644 --- a/src/mod_service_log.erl +++ b/src/mod_service_log.erl @@ -62,9 +62,7 @@ log_user_receive(Packet, _C2SState, _JID, From, To) -> log_packet(From, To, Packet, To#jid.lserver), Packet. -log_packet(From, To, - #xmlel{name = Name, attrs = Attrs, children = Els}, - Host) -> +log_packet(From, To, Packet, Host) -> Loggers = gen_mod:get_module_opt(Host, ?MODULE, loggers, fun(L) -> lists:map( @@ -76,22 +74,11 @@ log_packet(From, To, end end, L) end, []), - ServerJID = #jid{user = <<"">>, server = Host, - resource = <<"">>, luser = <<"">>, lserver = Host, - lresource = <<"">>}, - NewAttrs = - jlib:replace_from_to_attrs(jid:to_string(From), - jid:to_string(To), Attrs), - FixedPacket = #xmlel{name = Name, attrs = NewAttrs, - children = Els}, + ServerJID = jid:make(Host), + FixedPacket = xmpp:set_from_to(Packet, From, To), lists:foreach(fun (Logger) -> ejabberd_router:route(ServerJID, - #jid{user = <<"">>, - server = Logger, - resource = <<"">>, - luser = <<"">>, - lserver = Logger, - lresource = <<"">>}, + jid:make(Logger), #xmlel{name = <<"route">>, attrs = [], children = diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index f738648d6..b75b6575b 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -35,7 +35,7 @@ -export([start/2, init/3, stop/1, get_sm_features/5, process_local_iq/1, process_sm_iq/1, string2lower/1, remove_user/2, export/1, import/1, import/3, depends/2, - process_search/1, process_vcard/1, + process_search/1, process_vcard/1, get_vcard/2, disco_items/5, disco_features/5, disco_identity/5, mod_opt_type/1, set_vcard/3, make_vcard_search/4]). @@ -336,7 +336,7 @@ make_vcard_search(User, LUser, LServer, VCARD) -> orgunit = OrgUnit, lorgunit = LOrgUnit}. --spec set_vcard(binary(), binary(), xmlel()) -> any(). +-spec set_vcard(binary(), binary(), xmlel()) -> {error, badarg} | ok. set_vcard(User, LServer, VCARD) -> case jid:nodeprep(User) of error ->