aboutsummaryrefslogtreecommitdiff
path: root/src/mod_irc.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_irc.erl')
-rw-r--r--src/mod_irc.erl1233
1 files changed, 465 insertions, 768 deletions
diff --git a/src/mod_irc.erl b/src/mod_irc.erl
index e2203a306..2fb35414d 100644
--- a/src/mod_irc.erl
+++ b/src/mod_irc.erl
@@ -34,7 +34,8 @@
%% API
-export([start_link/2, start/2, stop/1, export/1, import/1,
import/3, closed_connection/3, get_connection_params/3,
- data_to_binary/2]).
+ data_to_binary/2, process_disco_info/1, process_disco_items/1,
+ process_register/1, process_vcard/1, process_command/1]).
-export([init/1, handle_call/3, handle_cast/2,
handle_info/2, terminate/2, code_change/3,
@@ -42,11 +43,7 @@
-include("ejabberd.hrl").
-include("logger.hrl").
-
--include("jlib.hrl").
-
--include("adhoc.hrl").
-
+-include("xmpp.hrl").
-include("mod_irc.hrl").
-define(DEFAULT_IRC_ENCODING, <<"iso8859-15">>).
@@ -69,10 +66,8 @@
-callback init(binary(), gen_mod:opts()) -> any().
-callback import(binary(), #irc_custom{}) -> ok | pass.
--callback get_data(binary(), binary(), {binary(), binary()}) ->
- error | empty | irc_data().
--callback set_data(binary(), binary(), {binary(), binary()}, irc_data()) ->
- {atomic, any()}.
+-callback get_data(binary(), binary(), jid()) -> error | empty | irc_data().
+-callback set_data(binary(), binary(), jid(), irc_data()) -> {atomic, any()}.
%%====================================================================
%% API
@@ -125,6 +120,18 @@ init([Host, Opts]) ->
catch ets:new(irc_connection,
[named_table, public,
{keypos, #irc_connection.jid_server_host}]),
+ IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1,
+ one_queue),
+ 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_REGISTER,
+ ?MODULE, process_register, 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_COMMANDS,
+ ?MODULE, process_command, IQDisc),
ejabberd_router:register_route(MyHost, Host),
{ok,
#state{host = MyHost, server_host = Host,
@@ -176,8 +183,13 @@ handle_info(_Info, State) -> {noreply, State}.
%% cleaning up. When it returns, the gen_server terminates with Reason.
%% The return value is ignored.
%%--------------------------------------------------------------------
-terminate(_Reason, State) ->
- ejabberd_router:unregister_route(State#state.host), ok.
+terminate(_Reason, #state{host = MyHost}) ->
+ 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_REGISTER),
+ gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_VCARD),
+ gen_iq_handler:remove_iq_handler(ejabberd_local, MyHost, ?NS_COMMANDS).
%%--------------------------------------------------------------------
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
@@ -203,287 +215,222 @@ stop_supervisor(Host) ->
supervisor:terminate_child(ejabberd_sup, Proc),
supervisor:delete_child(ejabberd_sup, Proc).
-do_route(Host, ServerHost, Access, From, To, Packet) ->
+do_route(Host, ServerHost, Access, From,
+ #jid{luser = LUser, lresource = LResource} = To, Packet) ->
case acl:match_rule(ServerHost, Access, From) of
- allow -> do_route1(Host, ServerHost, From, To, Packet);
- _ ->
- #xmlel{attrs = Attrs} = Packet,
- Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs),
- ErrText = <<"Access denied by service policy">>,
- Err = jlib:make_error_reply(Packet,
- ?ERRT_FORBIDDEN(Lang, ErrText)),
- ejabberd_router:route(To, From, Err)
+ allow ->
+ case Packet of
+ #iq{} when LUser == <<"">>, LResource == <<"">> ->
+ ejabberd_router:process_iq(From, To, Packet);
+ #iq{} when LUser == <<"">>, LResource /= <<"">> ->
+ Err = xmpp:err_service_unavailable(),
+ ejabberd_router:route_error(To, From, Packet, Err);
+ _ ->
+ sm_route(Host, ServerHost, From, To, Packet)
+ end;
+ deny ->
+ Lang = xmpp:get_lang(Packet),
+ Err = xmpp:err_forbidden(<<"Denied by ACL">>, Lang),
+ ejabberd_router:route_error(To, From, Packet, Err)
+ end.
+
+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, lang = Lang, to = To,
+ sub_els = [#disco_info{node = Node}]} = IQ) ->
+ ServerHost = ejabberd_router:host_of_route(To#jid.lserver),
+ Info = ejabberd_hooks:run_fold(disco_info, ServerHost,
+ [], [ServerHost, ?MODULE, <<"">>, <<"">>]),
+ case iq_disco(ServerHost, Node, Lang) of
+ undefined ->
+ xmpp:make_iq_result(IQ, #disco_info{});
+ DiscoInfo ->
+ xmpp:make_iq_result(IQ, DiscoInfo#disco_info{xdata = Info})
+ end.
+
+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, lang = Lang, to = To,
+ sub_els = [#disco_items{node = Node}]} = IQ) ->
+ case Node of
+ <<"">> ->
+ xmpp:make_iq_result(IQ, #disco_items{});
+ <<"join">> ->
+ xmpp:make_iq_result(IQ, #disco_items{});
+ <<"register">> ->
+ xmpp:make_iq_result(IQ, #disco_items{});
+ ?NS_COMMANDS ->
+ Host = To#jid.lserver,
+ ServerHost = ejabberd_router:host_of_route(Host),
+ xmpp:make_iq_result(
+ IQ, #disco_items{node = Node,
+ items = command_items(ServerHost, Host, Lang)});
+ _ ->
+ Txt = <<"Node not found">>,
+ xmpp:make_error(IQ, xmpp:err_item_not_found(Txt, Lang))
+ end.
+
+process_register(#iq{type = get, to = To, from = From, lang = Lang} = IQ) ->
+ Host = To#jid.lserver,
+ ServerHost = ejabberd_router:host_of_route(Host),
+ case get_form(ServerHost, Host, From, Lang) of
+ {result, Res} ->
+ xmpp:make_iq_result(IQ, Res);
+ {error, Error} ->
+ xmpp:make_error(IQ, Error)
+ end;
+process_register(#iq{type = set, lang = Lang, to = To, from = From,
+ sub_els = [#register{xdata = #xdata{} = X}]} = IQ) ->
+ case X#xdata.type of
+ cancel ->
+ xmpp:make_iq_result(IQ, #register{});
+ submit ->
+ Host = To#jid.lserver,
+ ServerHost = ejabberd_router:host_of_route(Host),
+ case set_form(ServerHost, Host, From, Lang, X) of
+ {result, Res} ->
+ xmpp:make_iq_result(IQ, Res);
+ {error, Error} ->
+ xmpp:make_error(IQ, Error)
+ end;
+ _ ->
+ Txt = <<"Incorrect value of 'type' attribute">>,
+ xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang))
+ end;
+process_register(#iq{type = set, lang = Lang} = IQ) ->
+ Txt = <<"No data form found">>,
+ xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)).
+
+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) ->
+ xmpp:make_iq_result(IQ, iq_get_vcard(Lang)).
+
+process_command(#iq{type = get, lang = Lang} = IQ) ->
+ Txt = <<"Value 'get' of 'type' attribute is not allowed">>,
+ xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang));
+process_command(#iq{type = set, lang = Lang, to = To, from = From,
+ sub_els = [#adhoc_command{node = Node} = Request]} = IQ) ->
+ Host = To#jid.lserver,
+ ServerHost = ejabberd_router:host_of_route(Host),
+ case lists:keyfind(Node, 1, commands(ServerHost)) of
+ {_, _, Function} ->
+ try Function(From, To, Request) of
+ ignore ->
+ ignore;
+ {error, Error} ->
+ xmpp:make_error(IQ, Error);
+ Command ->
+ xmpp:make_iq_result(IQ, Command)
+ catch E:R ->
+ ?ERROR_MSG("ad-hoc handler failed: ~p",
+ [{E, {R, erlang:get_stacktrace()}}]),
+ xmpp:make_error(IQ, xmpp:err_internal_server_error())
+ end;
+ _ ->
+ Txt = <<"Node not found">>,
+ xmpp:make_error(IQ, xmpp:err_item_not_found(Txt, Lang))
end.
-do_route1(Host, ServerHost, From, To, Packet) ->
+sm_route(Host, ServerHost, From, To, Packet) ->
#jid{user = ChanServ, resource = Resource} = To,
- #xmlel{} = Packet,
- case ChanServ of
- <<"">> ->
- case Resource of
- <<"">> ->
- case jlib:iq_query_info(Packet) of
- #iq{type = get, xmlns = (?NS_DISCO_INFO) = XMLNS,
- sub_el = SubEl, lang = Lang} =
- IQ ->
- Node = fxml:get_tag_attr_s(<<"node">>, SubEl),
- Info = ejabberd_hooks:run_fold(disco_info, ServerHost,
- [],
- [ServerHost, ?MODULE,
- <<"">>, <<"">>]),
- case iq_disco(ServerHost, Node, Lang) of
- [] ->
- Res = IQ#iq{type = result,
- sub_el =
- [#xmlel{name = <<"query">>,
- attrs =
- [{<<"xmlns">>, XMLNS}],
- children = []}]},
- ejabberd_router:route(To, From,
- jlib:iq_to_xml(Res));
- DiscoInfo ->
- Res = IQ#iq{type = result,
- sub_el =
- [#xmlel{name = <<"query">>,
- attrs =
- [{<<"xmlns">>, XMLNS}],
- children =
- DiscoInfo ++ Info}]},
- ejabberd_router:route(To, From, jlib:iq_to_xml(Res))
- end;
- #iq{type = get, xmlns = (?NS_DISCO_ITEMS) = XMLNS,
- sub_el = SubEl, lang = Lang} =
- IQ ->
- Node = fxml:get_tag_attr_s(<<"node">>, SubEl),
- case Node of
- <<>> ->
- ResIQ = IQ#iq{type = result,
- sub_el =
- [#xmlel{name = <<"query">>,
- attrs =
- [{<<"xmlns">>,
- XMLNS}],
- children = []}]},
- Res = jlib:iq_to_xml(ResIQ);
- <<"join">> ->
- ResIQ = IQ#iq{type = result,
- sub_el =
- [#xmlel{name = <<"query">>,
- attrs =
- [{<<"xmlns">>,
- XMLNS}],
- children = []}]},
- Res = jlib:iq_to_xml(ResIQ);
- <<"register">> ->
- ResIQ = IQ#iq{type = result,
- sub_el =
- [#xmlel{name = <<"query">>,
- attrs =
- [{<<"xmlns">>,
- XMLNS}],
- children = []}]},
- Res = jlib:iq_to_xml(ResIQ);
- ?NS_COMMANDS ->
- ResIQ = IQ#iq{type = result,
- sub_el =
- [#xmlel{name = <<"query">>,
- attrs =
- [{<<"xmlns">>, XMLNS},
- {<<"node">>, Node}],
- children =
- command_items(ServerHost,
- Host,
- Lang)}]},
- Res = jlib:iq_to_xml(ResIQ);
- _ ->
- Txt = <<"Node not found">>,
- Res = jlib:make_error_reply(
- Packet, ?ERRT_ITEM_NOT_FOUND(Lang, Txt))
- end,
- ejabberd_router:route(To, From, Res);
- #iq{xmlns = ?NS_REGISTER} = IQ ->
- process_register(ServerHost, Host, From, To, IQ);
- #iq{type = get, xmlns = (?NS_VCARD) = XMLNS,
- lang = Lang} =
- IQ ->
- Res = IQ#iq{type = result,
- sub_el =
- [#xmlel{name = <<"vCard">>,
- attrs = [{<<"xmlns">>, XMLNS}],
- children = iq_get_vcard(Lang)}]},
- ejabberd_router:route(To, From, jlib:iq_to_xml(Res));
- #iq{type = set, xmlns = ?NS_COMMANDS, lang = Lang,
- sub_el = SubEl} =
- IQ ->
- Request = adhoc:parse_request(IQ),
- case lists:keysearch(Request#adhoc_request.node, 1,
- commands(ServerHost))
- of
- {value, {_, _, Function}} ->
- case catch Function(From, To, Request) of
- {'EXIT', Reason} ->
- ?ERROR_MSG("~p~nfor ad-hoc handler of ~p",
- [Reason, {From, To, IQ}]),
- Res = IQ#iq{type = error,
- sub_el =
- [SubEl,
- ?ERR_INTERNAL_SERVER_ERROR]};
- ignore -> Res = ignore;
- {error, Error} ->
- Res = IQ#iq{type = error,
- sub_el = [SubEl, Error]};
- Command ->
- Res = IQ#iq{type = result, sub_el = [Command]}
- end,
- if Res /= ignore ->
- ejabberd_router:route(To, From,
- jlib:iq_to_xml(Res));
- true -> ok
- end;
- _ ->
- Txt = <<"Node not found">>,
- Err = jlib:make_error_reply(
- Packet, ?ERRT_ITEM_NOT_FOUND(Lang, Txt)),
- ejabberd_router:route(To, From, Err)
- end;
- #iq{} = _IQ ->
- Err = jlib:make_error_reply(Packet,
- ?ERR_FEATURE_NOT_IMPLEMENTED),
- ejabberd_router:route(To, From, Err);
- _ -> ok
- end;
- _ ->
- Err = jlib:make_error_reply(Packet, ?ERR_BAD_REQUEST),
- ejabberd_router:route(To, From, Err)
- end;
- _ ->
- case str:tokens(ChanServ, <<"%">>) of
- [<<_, _/binary>> = Channel, <<_, _/binary>> = Server] ->
- case ets:lookup(irc_connection, {From, Server, Host}) of
- [] ->
- ?DEBUG("open new connection~n", []),
- {Username, Encoding, Port, Password} =
- get_connection_params(Host, ServerHost, From, Server),
- ConnectionUsername = case Packet of
+ case str:tokens(ChanServ, <<"%">>) of
+ [<<_, _/binary>> = Channel, <<_, _/binary>> = Server] ->
+ case ets:lookup(irc_connection, {From, Server, Host}) of
+ [] ->
+ ?DEBUG("open new connection~n", []),
+ {Username, Encoding, Port, Password} =
+ get_connection_params(Host, ServerHost, From, Server),
+ ConnectionUsername = case Packet of
%% If the user tries to join a
%% chatroom, the packet for sure
%% contains the desired username.
- #xmlel{name = <<"presence">>} ->
- Resource;
+ #presence{} -> Resource;
%% Otherwise, there is no firm
%% conclusion from the packet.
%% Better to use the configured
%% username (which defaults to the
%% username part of the JID).
_ -> Username
- end,
- Ident = extract_ident(Packet),
- RemoteAddr = extract_ip_address(Packet),
- RealName = get_realname(ServerHost),
- WebircPassword = get_webirc_password(ServerHost),
- {ok, Pid} = mod_irc_connection:start(From, Host,
- ServerHost, Server,
- ConnectionUsername,
- Encoding, Port,
- Password, Ident, RemoteAddr, RealName, WebircPassword, ?MODULE),
- ets:insert(irc_connection,
- #irc_connection{jid_server_host =
- {From, Server, Host},
- pid = Pid}),
- mod_irc_connection:route_chan(Pid, Channel, Resource,
- Packet),
- ok;
- [R] ->
- Pid = R#irc_connection.pid,
- ?DEBUG("send to process ~p~n", [Pid]),
- mod_irc_connection:route_chan(Pid, Channel, Resource,
- Packet),
- ok
- end;
- _ ->
- Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet),
- case str:tokens(ChanServ, <<"!">>) of
- [<<_, _/binary>> = Nick, <<_, _/binary>> = Server] ->
- case ets:lookup(irc_connection, {From, Server, Host}) of
+ end,
+ Ident = extract_ident(Packet),
+ RemoteAddr = extract_ip_address(Packet),
+ RealName = get_realname(ServerHost),
+ WebircPassword = get_webirc_password(ServerHost),
+ {ok, Pid} = mod_irc_connection:start(
+ From, Host, ServerHost, Server,
+ ConnectionUsername, Encoding, Port,
+ Password, Ident, RemoteAddr, RealName,
+ WebircPassword, ?MODULE),
+ ets:insert(irc_connection,
+ #irc_connection{
+ jid_server_host = {From, Server, Host},
+ pid = Pid}),
+ mod_irc_connection:route_chan(Pid, Channel, Resource, Packet);
+ [R] ->
+ Pid = R#irc_connection.pid,
+ ?DEBUG("send to process ~p~n", [Pid]),
+ mod_irc_connection:route_chan(Pid, Channel, Resource, Packet)
+ end;
+ _ ->
+ Lang = xmpp:get_lang(Packet),
+ case str:tokens(ChanServ, <<"!">>) of
+ [<<_, _/binary>> = Nick, <<_, _/binary>> = Server] ->
+ case ets:lookup(irc_connection, {From, Server, Host}) of
[] ->
Txt = <<"IRC connection not found">>,
- Err = jlib:make_error_reply(
- Packet, ?ERRT_SERVICE_UNAVAILABLE(Lang, Txt)),
- ejabberd_router:route(To, From, Err);
+ Err = xmpp:err_service_unavailable(Txt, Lang),
+ ejabberd_router:route_error(To, From, Packet, Err);
[R] ->
Pid = R#irc_connection.pid,
?DEBUG("send to process ~p~n", [Pid]),
- mod_irc_connection:route_nick(Pid, Nick, Packet),
- ok
- end;
- _ ->
- Txt = <<"Failed to parse chanserv">>,
- Err = jlib:make_error_reply(
- Packet, ?ERRT_BAD_REQUEST(Lang, Txt)),
- ejabberd_router:route(To, From, Err)
- end
- end
+ mod_irc_connection:route_nick(Pid, Nick, Packet)
+ end;
+ _ ->
+ Txt = <<"Failed to parse chanserv">>,
+ Err = xmpp:err_bad_request(Txt, Lang),
+ ejabberd_router:route_error(To, From, Packet, Err)
+ end
end.
closed_connection(Host, From, Server) ->
ets:delete(irc_connection, {From, Server, Host}).
-iq_disco(_ServerHost, <<>>, Lang) ->
- [#xmlel{name = <<"identity">>,
- attrs =
- [{<<"category">>, <<"conference">>},
- {<<"type">>, <<"irc">>},
- {<<"name">>,
- translate:translate(Lang, <<"IRC Transport">>)}],
- children = []},
- #xmlel{name = <<"feature">>,
- attrs = [{<<"var">>, ?NS_DISCO_INFO}], children = []},
- #xmlel{name = <<"feature">>,
- attrs = [{<<"var">>, ?NS_MUC}], children = []},
- #xmlel{name = <<"feature">>,
- attrs = [{<<"var">>, ?NS_REGISTER}], children = []},
- #xmlel{name = <<"feature">>,
- attrs = [{<<"var">>, ?NS_VCARD}], children = []},
- #xmlel{name = <<"feature">>,
- attrs = [{<<"var">>, ?NS_COMMANDS}], children = []}];
+iq_disco(_ServerHost, <<"">>, Lang) ->
+ #disco_info{
+ identities = [#identity{category = <<"conference">>,
+ type = <<"irc">>,
+ name = translate:translate(Lang, <<"IRC Transport">>)}],
+ features = [?NS_DISCO_INFO, ?NS_DISCO_ITEMS, ?NS_MUC,
+ ?NS_REGISTER, ?NS_VCARD, ?NS_COMMANDS]};
iq_disco(ServerHost, Node, Lang) ->
- case lists:keysearch(Node, 1, commands(ServerHost)) of
- {value, {_, Name, _}} ->
- [#xmlel{name = <<"identity">>,
- attrs =
- [{<<"category">>, <<"automation">>},
- {<<"type">>, <<"command-node">>},
- {<<"name">>, translate:translate(Lang, Name)}],
- children = []},
- #xmlel{name = <<"feature">>,
- attrs = [{<<"var">>, ?NS_COMMANDS}], children = []},
- #xmlel{name = <<"feature">>,
- attrs = [{<<"var">>, ?NS_XDATA}], children = []}];
- _ -> []
+ case lists:keyfind(Node, 1, commands(ServerHost)) of
+ {_, Name, _} ->
+ #disco_info{
+ identities = [#identity{category = <<"automation">>,
+ type = <<"command-node">>,
+ name = translate:translate(Lang, Name)}],
+ features = [?NS_COMMANDS, ?NS_XDATA]};
+ _ ->
+ undefined
end.
iq_get_vcard(Lang) ->
- [#xmlel{name = <<"FN">>, attrs = [],
- children = [{xmlcdata, <<"ejabberd/mod_irc">>}]},
- #xmlel{name = <<"URL">>, attrs = [],
- children = [{xmlcdata, ?EJABBERD_URI}]},
- #xmlel{name = <<"DESC">>, attrs = [],
- children =
- [{xmlcdata,
- <<(translate:translate(Lang,
- <<"ejabberd IRC module">>))/binary,
- "\nCopyright (c) 2003-2016 ProcessOne">>}]}].
+ Desc = translate:translate(Lang, <<"ejabberd IRC module">>),
+ Copyright = <<"Copyright (c) 2003-2016 ProcessOne">>,
+ #vcard_temp{fn = <<"ejabberd/mod_irc">>,
+ url = ?EJABBERD_URI,
+ desc = <<Desc/binary, $\n, Copyright/binary>>}.
command_items(ServerHost, Host, Lang) ->
- lists:map(fun ({Node, Name, _Function}) ->
- #xmlel{name = <<"item">>,
- attrs =
- [{<<"jid">>, Host}, {<<"node">>, Node},
- {<<"name">>,
- translate:translate(Lang, Name)}],
- children = []}
- end,
- commands(ServerHost)).
+ lists:map(fun({Node, Name, _Function}) ->
+ #disco_item{jid = jid:make(Host),
+ node = Node,
+ name = translate:translate(Lang, Name)}
+ end, commands(ServerHost)).
commands(ServerHost) ->
[{<<"join">>, <<"Join channel">>, fun adhoc_join/3},
@@ -494,243 +441,120 @@ commands(ServerHost) ->
adhoc_register(ServerHost, From, To, Request)
end}].
-process_register(ServerHost, Host, From, To,
- #iq{} = IQ) ->
- case catch process_irc_register(ServerHost, Host, From,
- To, IQ)
- of
- {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]);
- ResIQ ->
- if ResIQ /= ignore ->
- ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ));
- true -> ok
- end
- end.
-
-find_xdata_el(#xmlel{children = SubEls}) ->
- find_xdata_el1(SubEls).
-
-find_xdata_el1([]) -> false;
-find_xdata_el1([#xmlel{name = Name, attrs = Attrs,
- children = SubEls}
- | Els]) ->
- case fxml:get_attr_s(<<"xmlns">>, Attrs) of
- ?NS_XDATA ->
- #xmlel{name = Name, attrs = Attrs, children = SubEls};
- _ -> find_xdata_el1(Els)
- end;
-find_xdata_el1([_ | Els]) -> find_xdata_el1(Els).
-
-process_irc_register(ServerHost, Host, From, _To,
- #iq{type = Type, xmlns = XMLNS, lang = Lang,
- sub_el = SubEl} =
- IQ) ->
- case Type of
- set ->
- XDataEl = find_xdata_el(SubEl),
- case XDataEl of
- false ->
- Txt1 = <<"No data form found">>,
- IQ#iq{type = error,
- sub_el = [SubEl, ?ERRT_NOT_ACCEPTABLE(Lang, Txt1)]};
- #xmlel{attrs = Attrs} ->
- case fxml:get_attr_s(<<"type">>, Attrs) of
- <<"cancel">> ->
- IQ#iq{type = result,
- sub_el =
- [#xmlel{name = <<"query">>,
- attrs = [{<<"xmlns">>, XMLNS}],
- children = []}]};
- <<"submit">> ->
- XData = jlib:parse_xdata_submit(XDataEl),
- case XData of
- invalid ->
- Txt2 = <<"Incorrect data form">>,
- IQ#iq{type = error,
- sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt2)]};
- _ ->
- Node = str:tokens(fxml:get_tag_attr_s(<<"node">>,
- SubEl),
- <<"/">>),
- case set_form(ServerHost, Host, From, Node, Lang,
- XData)
- of
- {result, Res} ->
- IQ#iq{type = result,
- sub_el =
- [#xmlel{name = <<"query">>,
- attrs =
- [{<<"xmlns">>, XMLNS}],
- children = Res}]};
- {error, Error} ->
- IQ#iq{type = error, sub_el = [SubEl, Error]}
- end
- end;
- _ ->
- Txt3 = <<"Incorrect value of 'type' attribute">>,
- IQ#iq{type = error,
- sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt3)]}
- end
- end;
- get ->
- Node = str:tokens(fxml:get_tag_attr_s(<<"node">>, SubEl),
- <<"/">>),
- case get_form(ServerHost, Host, From, Node, Lang) of
- {result, Res} ->
- IQ#iq{type = result,
- sub_el =
- [#xmlel{name = <<"query">>,
- attrs = [{<<"xmlns">>, XMLNS}],
- children = Res}]};
- {error, Error} ->
- IQ#iq{type = error, sub_el = [SubEl, Error]}
- end
- end.
-
get_data(ServerHost, Host, From) ->
LServer = jid:nameprep(ServerHost),
Mod = gen_mod:db_mod(LServer, ?MODULE),
Mod:get_data(LServer, Host, From).
-get_form(ServerHost, Host, From, [], Lang) ->
+get_form(ServerHost, Host, From, Lang) ->
#jid{user = User, server = Server} = From,
DefaultEncoding = get_default_encoding(Host),
Customs = case get_data(ServerHost, Host, From) of
- error ->
+ error ->
Txt1 = <<"Database failure">>,
- {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt1)};
- empty -> {User, []};
- Data -> get_username_and_connection_params(Data)
+ {error, xmpp:err_internal_server_error(Txt1, Lang)};
+ empty -> {User, []};
+ Data -> get_username_and_connection_params(Data)
end,
case Customs of
- {error, _Error} -> Customs;
- {Username, ConnectionsParams} ->
- {result,
- [#xmlel{name = <<"instructions">>, attrs = [],
- children =
- [{xmlcdata,
- translate:translate(Lang,
- <<"You need an x:data capable client to "
- "configure mod_irc settings">>)}]},
- #xmlel{name = <<"x">>,
- attrs = [{<<"xmlns">>, ?NS_XDATA}],
- children =
- [#xmlel{name = <<"title">>, attrs = [],
- children =
- [{xmlcdata,
- <<(translate:translate(Lang,
- <<"Registration in mod_irc for ">>))/binary,
- User/binary, "@", Server/binary>>}]},
- #xmlel{name = <<"instructions">>, attrs = [],
- children =
- [{xmlcdata,
- translate:translate(Lang,
- <<"Enter username, encodings, ports and "
- "passwords you wish to use for connecting "
- "to IRC servers">>)}]},
- #xmlel{name = <<"field">>,
- attrs =
- [{<<"type">>, <<"text-single">>},
- {<<"label">>,
- translate:translate(Lang,
- <<"IRC Username">>)},
- {<<"var">>, <<"username">>}],
- children =
- [#xmlel{name = <<"value">>, attrs = [],
- children = [{xmlcdata, Username}]}]},
- #xmlel{name = <<"field">>,
- attrs = [{<<"type">>, <<"fixed">>}],
- children =
- [#xmlel{name = <<"value">>, attrs = [],
- children =
- [{xmlcdata,
- iolist_to_binary(
- io_lib:format(
- translate:translate(
- Lang,
- <<"If you want to specify"
- " different ports, "
- "passwords, encodings "
- "for IRC servers, "
- "fill this list with "
- "values in format "
- "'{\"irc server\", "
- "\"encoding\", port, "
- "\"password\"}'. "
- "By default this "
- "service use \"~s\" "
- "encoding, port ~p, "
- "empty password.">>),
- [DefaultEncoding,
- ?DEFAULT_IRC_PORT]))}]}]},
- #xmlel{name = <<"field">>,
- attrs = [{<<"type">>, <<"fixed">>}],
- children =
- [#xmlel{name = <<"value">>, attrs = [],
- children =
- [{xmlcdata,
- translate:translate(Lang,
- <<"Example: [{\"irc.lucky.net\", \"koi8-r\", "
- "6667, \"secret\"}, {\"vendetta.fef.net\", "
- "\"iso8859-1\", 7000}, {\"irc.sometestserver.n"
- "et\", \"utf-8\"}].">>)}]}]},
- #xmlel{name = <<"field">>,
- attrs =
- [{<<"type">>, <<"text-multi">>},
- {<<"label">>,
- translate:translate(Lang,
- <<"Connections parameters">>)},
- {<<"var">>, <<"connections_params">>}],
- children =
- lists:map(fun (S) ->
- #xmlel{name = <<"value">>,
- attrs = [],
- children =
- [{xmlcdata, S}]}
- end,
- str:tokens(list_to_binary(
- io_lib:format(
- "~p.",
- [conn_params_to_list(
- ConnectionsParams)])),
- <<"\n">>))}]}]}
- end;
-get_form(_ServerHost, _Host, _, _, _Lang) ->
- {error, ?ERR_SERVICE_UNAVAILABLE}.
+ {error, _Error} ->
+ Customs;
+ {Username, ConnectionsParams} ->
+ Fs = [#xdata_field{type = 'text-single',
+ label = translate:translate(Lang, <<"IRC Username">>),
+ var = <<"username">>,
+ values = [Username]},
+ #xdata_field{type = fixed,
+ values = [iolist_to_binary(
+ io_lib:format(
+ translate:translate(
+ Lang,
+ <<"If you want to specify"
+ " different ports, "
+ "passwords, encodings "
+ "for IRC servers, "
+ "fill this list with "
+ "values in format "
+ "'{\"irc server\", "
+ "\"encoding\", port, "
+ "\"password\"}'. "
+ "By default this "
+ "service use \"~s\" "
+ "encoding, port ~p, "
+ "empty password.">>),
+ [DefaultEncoding, ?DEFAULT_IRC_PORT]))]},
+ #xdata_field{type = fixed,
+ values = [translate:translate(
+ Lang,
+ <<"Example: [{\"irc.lucky.net\", \"koi8-r\", "
+ "6667, \"secret\"}, {\"vendetta.fef.net\", "
+ "\"iso8859-1\", 7000}, {\"irc.sometestserver.n"
+ "et\", \"utf-8\"}].">>)]},
+ #xdata_field{type = 'text-multi',
+ label = translate:translate(
+ Lang, <<"Connections parameters">>),
+ var = <<"connections_params">>,
+ values = str:tokens(list_to_binary(
+ io_lib:format(
+ "~p.",
+ [conn_params_to_list(
+ ConnectionsParams)])),
+ <<"\n">>)}],
+ X = #xdata{type = form,
+ title = <<(translate:translate(
+ Lang, <<"Registration in mod_irc for ">>))/binary,
+ User/binary, "@", Server/binary>>,
+ instructions =
+ [translate:translate(
+ Lang,
+ <<"Enter username, encodings, ports and "
+ "passwords you wish to use for connecting "
+ "to IRC servers">>)],
+ fields = Fs},
+ {result,
+ #register{instructions =
+ translate:translate(Lang,
+ <<"You need an x:data capable client to "
+ "configure mod_irc settings">>),
+ xdata = X}}
+ end.
set_data(ServerHost, Host, From, Data) ->
LServer = jid:nameprep(ServerHost),
Mod = gen_mod:db_mod(LServer, ?MODULE),
Mod:set_data(LServer, Host, From, data_to_binary(From, Data)).
-set_form(ServerHost, Host, From, [], Lang, XData) ->
- case {lists:keysearch(<<"username">>, 1, XData),
- lists:keysearch(<<"connections_params">>, 1, XData)}
- of
- {{value, {_, [Username]}}, {value, {_, Strings}}} ->
- EncString = lists:foldl(fun (S, Res) ->
- <<Res/binary, S/binary, "\n">>
- end,
- <<"">>, Strings),
- case erl_scan:string(binary_to_list(EncString)) of
- {ok, Tokens, _} ->
- case erl_parse:parse_term(Tokens) of
- {ok, ConnectionsParams} ->
- case set_data(ServerHost, Host, From,
- [{username, Username},
- {connections_params, ConnectionsParams}])
- of
- {atomic, _} -> {result, []};
- _ -> {error, ?ERRT_NOT_ACCEPTABLE(Lang, <<"Database failure">>)}
- end;
- _ -> {error, ?ERRT_NOT_ACCEPTABLE(Lang, <<"Parse error">>)}
- end;
- _ -> {error, ?ERRT_NOT_ACCEPTABLE(Lang, <<"Scan error">>)}
- end;
- _ -> {error, ?ERR_NOT_ACCEPTABLE}
- end;
-set_form(_ServerHost, _Host, _, _, _Lang, _XData) ->
- {error, ?ERR_SERVICE_UNAVAILABLE}.
+set_form(ServerHost, Host, From, Lang, XData) ->
+ case {xmpp_util:get_xdata_values(<<"username">>, XData),
+ xmpp_util:get_xdata_values(<<"connections_params">>, XData)} of
+ {[Username], [_|_] = Strings} ->
+ EncString = lists:foldl(fun (S, Res) ->
+ <<Res/binary, S/binary, "\n">>
+ end, <<"">>, Strings),
+ case erl_scan:string(binary_to_list(EncString)) of
+ {ok, Tokens, _} ->
+ case erl_parse:parse_term(Tokens) of
+ {ok, ConnectionsParams} ->
+ case set_data(ServerHost, Host, From,
+ [{username, Username},
+ {connections_params, ConnectionsParams}]) of
+ {atomic, _} ->
+ {result, undefined};
+ _ ->
+ Txt = <<"Database failure">>,
+ {error, xmpp:err_internal_server_error(Txt, Lang)}
+ end;
+ _ ->
+ Txt = <<"Parse error">>,
+ {error, xmpp:err_not_acceptable(Txt, Lang)}
+ end;
+ _ ->
+ {error, xmpp:err_not_acceptable(<<"Scan error">>, Lang)}
+ end;
+ _ ->
+ Txt = <<"Incorrect value in data form">>,
+ {error, xmpp:err_not_acceptable(Txt, Lang)}
+ end.
get_connection_params(Host, From, IRCServer) ->
[_ | HostTail] = str:tokens(Host, <<".">>),
@@ -805,212 +629,118 @@ get_connection_params(Host, ServerHost, From,
iolist_to_binary(NewPassword)}
end.
-adhoc_join(_From, _To,
- #adhoc_request{action = <<"cancel">>} = Request) ->
- adhoc:produce_response(Request,
- #adhoc_response{status = canceled});
-adhoc_join(From, To,
- #adhoc_request{lang = Lang, node = _Node,
- action = _Action, xdata = XData} =
- Request) ->
- if XData == false ->
- Form = #xmlel{name = <<"x">>,
- attrs =
- [{<<"xmlns">>, ?NS_XDATA},
- {<<"type">>, <<"form">>}],
- children =
- [#xmlel{name = <<"title">>, attrs = [],
- children =
- [{xmlcdata,
- translate:translate(Lang,
- <<"Join IRC channel">>)}]},
- #xmlel{name = <<"field">>,
- attrs =
- [{<<"var">>, <<"channel">>},
- {<<"type">>, <<"text-single">>},
- {<<"label">>,
- translate:translate(Lang,
- <<"IRC channel (don't put the first #)">>)}],
- children =
- [#xmlel{name = <<"required">>,
- attrs = [], children = []}]},
- #xmlel{name = <<"field">>,
- attrs =
- [{<<"var">>, <<"server">>},
- {<<"type">>, <<"text-single">>},
- {<<"label">>,
- translate:translate(Lang,
- <<"IRC server">>)}],
- children =
- [#xmlel{name = <<"required">>,
- attrs = [], children = []}]}]},
- adhoc:produce_response(Request,
- #adhoc_response{status = executing,
- elements = [Form]});
+adhoc_join(_From, _To, #adhoc_command{action = cancel} = Request) ->
+ xmpp_util:make_adhoc_response(Request, #adhoc_command{status = canceled});
+adhoc_join(_From, _To, #adhoc_command{lang = Lang, xdata = undefined} = Request) ->
+ X = #xdata{type = form,
+ title = translate:translate(Lang, <<"Join IRC channel">>),
+ fields = [#xdata_field{var = <<"channel">>,
+ type = 'text-single',
+ label = translate:translate(
+ Lang, <<"IRC channel (don't put the first #)">>),
+ required = true},
+ #xdata_field{var = <<"server">>,
+ type = 'text-single',
+ label = translate:translate(Lang, <<"IRC server">>),
+ required = true}]},
+ xmpp_util:make_adhoc_response(
+ Request, #adhoc_command{status = executing, xdata = X});
+adhoc_join(From, To, #adhoc_command{lang = Lang, xdata = X} = Request) ->
+ Channel = case xmpp_util:get_xdata_values(<<"channel">>, X) of
+ [C] -> C;
+ _ -> false
+ end,
+ Server = case xmpp_util:get_xdata_values(<<"server">>, X) of
+ [S] -> S;
+ _ -> false
+ end,
+ if Channel /= false, Server /= false ->
+ RoomJID = jid:make(<<Channel/binary, "%", Server/binary>>,
+ To#jid.server),
+ Reason = translate:translate(Lang, <<"Join the IRC channel here.">>),
+ Body = iolist_to_binary(
+ io_lib:format(
+ translate:translate(
+ Lang, <<"Join the IRC channel in this Jabber ID: ~s">>),
+ [jid:to_string(RoomJID)])),
+ Invite = #message{
+ body = xmpp:mk_text(Body, Lang),
+ sub_els = [#muc_user{
+ invites = [#muc_invite{from = From,
+ reason = Reason}]},
+ #x_conference{reason = Reason,
+ jid = RoomJID}]},
+ ejabberd_router:route(RoomJID, From, Invite),
+ xmpp_util:make_adhoc_response(
+ Request, #adhoc_command{status = completed});
true ->
- case jlib:parse_xdata_submit(XData) of
- invalid ->
- Txt1 = <<"Incorrect data form">>,
- {error, ?ERRT_BAD_REQUEST(Lang, Txt1)};
- Fields ->
- Channel = case lists:keysearch(<<"channel">>, 1, Fields)
- of
- {value, {<<"channel">>, [C]}} -> C;
- _ -> false
- end,
- Server = case lists:keysearch(<<"server">>, 1, Fields)
- of
- {value, {<<"server">>, [S]}} -> S;
- _ -> false
- end,
- if Channel /= false, Server /= false ->
- RoomJID = <<Channel/binary, "%", Server/binary, "@",
- (To#jid.server)/binary>>,
- Invite = #xmlel{name = <<"message">>, attrs = [],
- children =
- [#xmlel{name = <<"x">>,
- attrs =
- [{<<"xmlns">>,
- ?NS_MUC_USER}],
- children =
- [#xmlel{name =
- <<"invite">>,
- attrs =
- [{<<"from">>,
- jid:to_string(From)}],
- children =
- [#xmlel{name
- =
- <<"reason">>,
- attrs
- =
- [],
- children
- =
- [{xmlcdata,
- translate:translate(Lang,
- <<"Join the IRC channel here.">>)}]}]}]},
- #xmlel{name = <<"x">>,
- attrs =
- [{<<"xmlns">>,
- ?NS_XCONFERENCE}],
- children =
- [{xmlcdata,
- translate:translate(Lang,
- <<"Join the IRC channel here.">>)}]},
- #xmlel{name = <<"body">>,
- attrs = [],
- children =
- [{xmlcdata,
- iolist_to_binary(
- io_lib:format(
- translate:translate(
- Lang,
- <<"Join the IRC channel in this Jabber ID: ~s">>),
- [RoomJID]))}]}]},
- ejabberd_router:route(jid:from_string(RoomJID), From,
- Invite),
- adhoc:produce_response(Request,
- #adhoc_response{status =
- completed});
- true -> {error, ?ERR_BAD_REQUEST}
- end
- end
+ Txt = <<"Missing 'channel' or 'server' in the data form">>,
+ {error, xmpp:err_bad_request(Txt, Lang)}
end.
+-spec adhoc_register(binary(), jid(), jid(), adhoc_command()) ->
+ adhoc_command() | {error, stanza_error()}.
adhoc_register(_ServerHost, _From, _To,
- #adhoc_request{action = <<"cancel">>} = Request) ->
- adhoc:produce_response(Request,
- #adhoc_response{status = canceled});
+ #adhoc_command{action = cancel} = Request) ->
+ xmpp_util:make_adhoc_response(Request, #adhoc_command{status = canceled});
adhoc_register(ServerHost, From, To,
- #adhoc_request{lang = Lang, node = _Node, xdata = XData,
- action = Action} =
- Request) ->
+ #adhoc_command{lang = Lang, xdata = X,
+ action = Action} = Request) ->
#jid{user = User} = From,
#jid{lserver = Host} = To,
- if XData == false ->
- case get_data(ServerHost, Host, From) of
- error -> Username = User, ConnectionsParams = [];
- empty -> Username = User, ConnectionsParams = [];
- Data ->
- {Username, ConnectionsParams} =
- get_username_and_connection_params(Data)
- end,
- Error = false;
- true ->
- case jlib:parse_xdata_submit(XData) of
- invalid ->
- Txt1 = <<"Incorrect data form">>,
- Error = {error, ?ERRT_BAD_REQUEST(Lang, Txt1)},
- Username = false,
- ConnectionsParams = false;
- Fields ->
- Username = case lists:keysearch(<<"username">>, 1,
- Fields)
- of
- {value, {<<"username">>, U}} -> U;
- _ -> User
- end,
- ConnectionsParams = parse_connections_params(Fields),
- Error = false
- end
- end,
- if Error /= false -> Error;
- Action == <<"complete">> ->
- case set_data(ServerHost, Host, From,
- [{username, Username},
- {connections_params, ConnectionsParams}])
- of
- {atomic, _} ->
- adhoc:produce_response(Request,
- #adhoc_response{status = completed});
- _ ->
- Txt2 = <<"Database failure">>,
- {error, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt2)}
- end;
+ {Username, ConnectionsParams} =
+ if X == undefined ->
+ case get_data(ServerHost, Host, From) of
+ error -> {User, []};
+ empty -> {User, []};
+ Data -> get_username_and_connection_params(Data)
+ end;
+ true ->
+ {case xmpp_util:get_xdata_values(<<"username">>, X) of
+ [U] -> U;
+ _ -> User
+ end, parse_connections_params(X)}
+ end,
+ if Action == complete ->
+ case set_data(ServerHost, Host, From,
+ [{username, Username},
+ {connections_params, ConnectionsParams}]) of
+ {atomic, _} ->
+ xmpp_util:make_adhoc_response(
+ Request, #adhoc_command{status = completed});
+ _ ->
+ Txt = <<"Database failure">>,
+ {error, xmpp:err_internal_server_error(Txt, Lang)}
+ end;
true ->
- Form = generate_adhoc_register_form(Lang, Username,
- ConnectionsParams),
- adhoc:produce_response(Request,
- #adhoc_response{status = executing,
- elements = [Form],
- actions =
- [<<"next">>,
- <<"complete">>]})
+ Form = generate_adhoc_register_form(Lang, Username,
+ ConnectionsParams),
+ xmpp_util:make_adhoc_response(
+ Request, #adhoc_command{
+ status = executing,
+ xdata = Form,
+ actions = #adhoc_actions{next = true,
+ complete = true}})
end.
generate_adhoc_register_form(Lang, Username,
ConnectionsParams) ->
- #xmlel{name = <<"x">>,
- attrs =
- [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"form">>}],
- children =
- [#xmlel{name = <<"title">>, attrs = [],
- children =
- [{xmlcdata,
- translate:translate(Lang, <<"IRC settings">>)}]},
- #xmlel{name = <<"instructions">>, attrs = [],
- children =
- [{xmlcdata,
- translate:translate(Lang,
- <<"Enter username and encodings you wish "
- "to use for connecting to IRC servers. "
- " Press 'Next' to get more fields to "
- "fill in. Press 'Complete' to save settings.">>)}]},
- #xmlel{name = <<"field">>,
- attrs =
- [{<<"var">>, <<"username">>},
- {<<"type">>, <<"text-single">>},
- {<<"label">>,
- translate:translate(Lang, <<"IRC username">>)}],
- children =
- [#xmlel{name = <<"required">>, attrs = [],
- children = []},
- #xmlel{name = <<"value">>, attrs = [],
- children = [{xmlcdata, Username}]}]}]
- ++
- generate_connection_params_fields(Lang,
- ConnectionsParams, 1, [])}.
+ #xdata{type = form,
+ title = translate:translate(Lang, <<"IRC settings">>),
+ instructions = [translate:translate(
+ Lang,
+ <<"Enter username and encodings you wish "
+ "to use for connecting to IRC servers. "
+ " Press 'Next' to get more fields to "
+ "fill in. Press 'Complete' to save settings.">>)],
+ fields = [#xdata_field{
+ var = <<"username">>,
+ type = 'text-single',
+ label = translate:translate(Lang, <<"IRC username">>),
+ required = true,
+ values = [Username]}
+ | generate_connection_params_fields(
+ Lang, ConnectionsParams, 1, [])]}.
generate_connection_params_fields(Lang, [], Number,
Acc) ->
@@ -1061,91 +791,67 @@ generate_connection_params_field(Lang, Server, Encoding,
end,
NumberString =
iolist_to_binary(integer_to_list(Number)),
- [#xmlel{name = <<"field">>,
- attrs =
- [{<<"var">>, <<"password", NumberString/binary>>},
- {<<"type">>, <<"text-single">>},
- {<<"label">>,
- iolist_to_binary(
- io_lib:format(
- translate:translate(Lang, <<"Password ~b">>),
- [Number]))}],
- children =
- [#xmlel{name = <<"value">>, attrs = [],
- children = [{xmlcdata, PasswordUsed}]}]},
- #xmlel{name = <<"field">>,
- attrs =
- [{<<"var">>, <<"port", NumberString/binary>>},
- {<<"type">>, <<"text-single">>},
- {<<"label">>,
- iolist_to_binary(
- io_lib:format(translate:translate(Lang, <<"Port ~b">>),
- [Number]))}],
- children =
- [#xmlel{name = <<"value">>, attrs = [],
- children = [{xmlcdata, PortUsed}]}]},
- #xmlel{name = <<"field">>,
- attrs =
- [{<<"var">>, <<"encoding", NumberString/binary>>},
- {<<"type">>, <<"list-single">>},
- {<<"label">>,
- list_to_binary(
- io_lib:format(translate:translate(
- Lang,
- <<"Encoding for server ~b">>),
- [Number]))}],
- children =
- [#xmlel{name = <<"value">>, attrs = [],
- children = [{xmlcdata, EncodingUsed}]}
- | lists:map(fun (E) ->
- #xmlel{name = <<"option">>,
- attrs = [{<<"label">>, E}],
- children =
- [#xmlel{name = <<"value">>,
- attrs = [],
- children =
- [{xmlcdata, E}]}]}
- end,
- ?POSSIBLE_ENCODINGS)]},
- #xmlel{name = <<"field">>,
- attrs =
- [{<<"var">>, <<"server", NumberString/binary>>},
- {<<"type">>, <<"text-single">>},
- {<<"label">>,
- list_to_binary(
- io_lib:format(translate:translate(Lang, <<"Server ~b">>),
- [Number]))}],
- children =
- [#xmlel{name = <<"value">>, attrs = [],
- children = [{xmlcdata, Server}]}]}].
-
-parse_connections_params(Fields) ->
+ [#xdata_field{var = <<"password", NumberString/binary>>,
+ type = 'text-single',
+ label = iolist_to_binary(
+ io_lib:format(
+ translate:translate(Lang, <<"Password ~b">>),
+ [Number])),
+ values = [PasswordUsed]},
+ #xdata_field{var = <<"port", NumberString/binary>>,
+ type = 'text-single',
+ label = iolist_to_binary(
+ io_lib:format(
+ translate:translate(Lang, <<"Port ~b">>),
+ [Number])),
+ values = [PortUsed]},
+ #xdata_field{var = <<"encoding", NumberString/binary>>,
+ type = 'list-single',
+ label = list_to_binary(
+ io_lib:format(
+ translate:translate(Lang, <<"Encoding for server ~b">>),
+ [Number])),
+ values = [EncodingUsed],
+ options = [#xdata_option{label = E, value = E}
+ || E <- ?POSSIBLE_ENCODINGS]},
+ #xdata_field{var = <<"server", NumberString/binary>>,
+ type = 'text-single',
+ label = list_to_binary(
+ io_lib:format(
+ translate:translate(Lang, <<"Server ~b">>),
+ [Number])),
+ values = [Server]}].
+
+parse_connections_params(#xdata{fields = Fields}) ->
Servers = lists:flatmap(
- fun({<<"server", Var/binary>>, Value}) ->
- [{Var, Value}];
+ fun(#xdata_field{var = <<"server", Var/binary>>,
+ values = Values}) ->
+ [{Var, Values}];
(_) ->
[]
end, Fields),
Encodings = lists:flatmap(
- fun({<<"encoding", Var/binary>>, Value}) ->
- [{Var, Value}];
+ fun(#xdata_field{var = <<"encoding", Var/binary>>,
+ values = Values}) ->
+ [{Var, Values}];
(_) ->
[]
end, Fields),
Ports = lists:flatmap(
- fun({<<"port", Var/binary>>, Value}) ->
- [{Var, Value}];
+ fun(#xdata_field{var = <<"port", Var/binary>>,
+ values = Values}) ->
+ [{Var, Values}];
(_) ->
[]
end, Fields),
Passwords = lists:flatmap(
- fun({<<"password", Var/binary>>, Value}) ->
- [{Var, Value}];
+ fun(#xdata_field{var = <<"password", Var/binary>>,
+ values = Values}) ->
+ [{Var, Values}];
(_) ->
[]
end, Fields),
- parse_connections_params(Servers, Encodings, Ports,
- Passwords).
+ parse_connections_params(Servers, Encodings, Ports, Passwords).
retrieve_connections_params(ConnectionParams,
ServerN) ->
@@ -1263,28 +969,19 @@ mod_opt_type(host) -> fun iolist_to_binary/1;
mod_opt_type(_) ->
[access, db_type, default_encoding, host].
+-spec extract_ident(stanza()) -> binary().
extract_ident(Packet) ->
- case fxml:get_subtag(Packet, <<"headers">>) of
- {xmlel, _Name, _Attrs, Headers} ->
- extract_header(<<"X-Irc-Ident">>, Headers);
- _ ->
- "chatmovil"
- end.
+ Hdrs = extract_headers(Packet),
+ proplists:get_value(<<"X-Irc-Ident">>, Hdrs, <<"chatmovil">>).
+-spec extract_ip_address(stanza()) -> binary().
extract_ip_address(Packet) ->
- case fxml:get_subtag(Packet, <<"headers">>) of
- {xmlel, _Name, _Attrs, Headers} ->
- extract_header(<<"X-Forwarded-For">>, Headers);
- _ ->
- "127.0.0.1"
+ Hdrs = extract_headers(Packet),
+ proplists:get_value(<<"X-Forwarded-For">>, Hdrs, <<"127.0.0.1">>).
+
+-spec extract_headers(stanza()) -> [{binary(), binary()}].
+extract_headers(Packet) ->
+ case xmpp:get_subtag(Packet, #shim{}) of
+ #shim{headers = Hs} -> Hs;
+ false -> []
end.
-
-extract_header(HeaderName, [{xmlel, _Name, _Attrs, [{xmlcdata, Value}]} | Tail]) ->
- case fxml:get_attr(<<"name">>, _Attrs) of
- {value, HeaderName} ->
- binary_to_list(Value);
- _ ->
- extract_header(HeaderName, Tail)
- end;
-extract_header(_HeaderName, _Headers) ->
- false.