]> granicus.if.org Git - ejabberd/commitdiff
Rewrite mod_sic to use XML generator
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>
Sat, 30 Jul 2016 10:30:29 +0000 (13:30 +0300)
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>
Sat, 30 Jul 2016 10:30:29 +0000 (13:30 +0300)
include/ns.hrl
include/xmpp_codec.hrl
src/mod_sic.erl
src/xmpp_codec.erl
tools/xmpp_codec.spec

index b301615658f3eacdcda6d5f8b8bf75cf64274670..7955129efe5cb4f3c46219c8eb7f8544694b26e9 100644 (file)
 -define(NS_HTTP_UPLOAD_OLD, <<"eu:siacs:conversations:http:upload">>).
 -define(NS_THUMBS_1, <<"urn:xmpp:thumbs:1">>).
 -define(NS_NICK,  <<"http://jabber.org/protocol/nick">>).
+-define(NS_SIC_0, <<"urn:xmpp:sic:0">>).
+-define(NS_SIC_1, <<"urn:xmpp:sic:1">>).
 -define(NS_MIX_0, <<"urn:xmpp:mix:0">>).
 -define(NS_MIX_SERVICEINFO_0, <<"urn:xmpp:mix:0#serviceinfo">>).
 -define(NS_MIX_NODES_MESSAGES, <<"urn:xmpp:mix:nodes:messages">>).
index 1ede0ff1df44b69d86749429be154b14ec73dec7..88c94a76b5d34f55d5a2b61658a9a6bcf8efc474 100644 (file)
                        items = [] :: [#pubsub_item{}]}).
 -type pubsub_items() :: #pubsub_items{}.
 
+-record(sic, {ip :: any(),
+              port :: non_neg_integer(),
+              xmlns :: binary()}).
+-type sic() :: #sic{}.
+
 -record(carbons_sent, {forwarded :: #forwarded{}}).
 -type carbons_sent() :: #carbons_sent{}.
 
                         muc_decline() |
                         legacy_auth() |
                         search() |
-                        unblock() |
                         nick() |
                         p1_ack() |
                         block() |
                         stream_features() |
                         stats() |
                         pubsub_items() |
+                        sic() |
                         starttls() |
                         mam_prefs() |
                         sasl_mechanisms() |
                         sasl_auth() |
                         p1_push() |
                         oob_x() |
-                        pubsub_publish().
+                        pubsub_publish() |
+                        unblock().
index 49b65a0eef58a2719b01619434223652097b7e88..4bb4eb9eb34cc5a9d7bf03251a4dae87ab3441c0 100644 (file)
 
 -behaviour(gen_mod).
 
--export([start/2, stop/1, process_local_iq/3,
-        process_sm_iq/3, mod_opt_type/1, depends/2]).
+-export([start/2, stop/1, process_local_iq/1,
+        process_sm_iq/1, mod_opt_type/1, depends/2]).
 
 -include("ejabberd.hrl").
 -include("logger.hrl").
-
--include("jlib.hrl").
-
--define(NS_SIC, <<"urn:xmpp:sic:0">>).
+-include("xmpp.hrl").
 
 start(Host, Opts) ->
     IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1,
                              one_queue),
-    gen_iq_handler:add_iq_handler(ejabberd_local, Host,
-                                 ?NS_SIC, ?MODULE, process_local_iq, IQDisc),
-    gen_iq_handler:add_iq_handler(ejabberd_sm, Host,
-                                 ?NS_SIC, ?MODULE, process_sm_iq, IQDisc).
+    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_SIC_0,
+                                 ?MODULE, process_local_iq, IQDisc),
+    gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_SIC_0,
+                                 ?MODULE, process_sm_iq, IQDisc),    
+    gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_SIC_1,
+                                 ?MODULE, process_local_iq, IQDisc),
+    gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_SIC_1,
+                                 ?MODULE, process_sm_iq, IQDisc).
 
 stop(Host) ->
-    gen_iq_handler:remove_iq_handler(ejabberd_local, Host,
-                                    ?NS_SIC),
-    gen_iq_handler:remove_iq_handler(ejabberd_sm, Host,
-                                    ?NS_SIC).
+    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_SIC_0),
+    gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_SIC_0),
+    gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_SIC_1),
+    gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_SIC_1).
 
 depends(_Host, _Opts) ->
     [].
 
-process_local_iq(#jid{user = User, server = Server,
-                     resource = Resource},
-                _To, #iq{type = get, sub_el = _SubEl} = IQ) ->
+process_local_iq(#iq{from = #jid{user = User, server = Server,
+                                resource = Resource},
+                    type = get} = IQ) ->
     get_ip({User, Server, Resource}, IQ);
-process_local_iq(_From, _To,
-                #iq{type = set, sub_el = SubEl, lang = Lang} = IQ) ->
+process_local_iq(#iq{type = set, lang = Lang} = IQ) ->
     Txt = <<"Value 'set' of 'type' attribute is not allowed">>,
-    IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}.
+    xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)).
 
-process_sm_iq(#jid{user = User, server = Server,
-                  resource = Resource},
-             #jid{user = User, server = Server},
-             #iq{type = get, sub_el = _SubEl} = IQ) ->
+process_sm_iq(#iq{from = #jid{user = User, server = Server,
+                             resource = Resource},
+                 to = #jid{user = User, server = Server},
+                 type = get} = IQ) ->
     get_ip({User, Server, Resource}, IQ);
-process_sm_iq(_From, _To,
-             #iq{type = get, sub_el = SubEl, lang = Lang} = IQ) ->
+process_sm_iq(#iq{type = get, lang = Lang} = IQ) ->
     Txt = <<"Query to another users is forbidden">>,
-    IQ#iq{type = error, sub_el = [SubEl, ?ERRT_FORBIDDEN(Lang, Txt)]};
-process_sm_iq(_From, _To,
-             #iq{type = set, sub_el = SubEl, lang = Lang} = IQ) ->
+    xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang));
+process_sm_iq(#iq{type = set, lang = Lang} = IQ) ->
     Txt = <<"Value 'set' of 'type' attribute is not allowed">>,
-    IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]}.
+    xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)).
 
 get_ip({User, Server, Resource},
-       #iq{lang = Lang,
-          sub_el =
-              #xmlel{name = Name, attrs = Attrs} = SubEl} =
-          IQ) ->
+       #iq{lang = Lang, sub_els = [#sic{xmlns = NS}]} = IQ) ->
     case ejabberd_sm:get_user_ip(User, Server, Resource) of
-      {IP, _} when is_tuple(IP) ->
-         IQ#iq{type = result,
-               sub_el =
-                   [#xmlel{name = Name, attrs = Attrs,
-                           children =
-                               [{xmlcdata,
-                                 iolist_to_binary(jlib:ip_to_list(IP))}]}]};
-      _ ->
-         Txt = <<"User session not found">>,
-         IQ#iq{type = error,
-               sub_el = [SubEl, ?ERRT_INTERNAL_SERVER_ERROR(Lang, Txt)]}
+       {IP, Port} when is_tuple(IP) ->
+           Result = case NS of
+                        ?NS_SIC_0 -> #sic{ip = IP, xmlns = NS};
+                        ?NS_SIC_1 -> #sic{ip = IP, port = Port, xmlns = NS}
+                    end,
+           xmpp:make_iq_result(IQ, Result);
+       _ ->
+           Txt = <<"User session not found">>,
+           xmpp:make_error(IQ, xmpp:err_item_not_found(Txt, Lang))
     end.
 
 mod_opt_type(iqdisc) -> fun gen_iq_handler:check_type/1;
index 113be860be8da08b0040f114ce668cbe5680c95c..11bd741f41dbaf4a5159c2e8e58f3496dff91ae5 100644 (file)
@@ -15,6 +15,16 @@ decode(_el) -> decode(_el, []).
 decode({xmlel, _name, _attrs, _} = _el, Opts) ->
     IgnoreEls = proplists:get_bool(ignore_els, Opts),
     case {_name, get_attr(<<"xmlns">>, _attrs)} of
+      {<<"address">>, <<"urn:xmpp:sic:0">>} ->
+         decode_sic(<<"urn:xmpp:sic:0">>, IgnoreEls, _el);
+      {<<"address">>, <<"urn:xmpp:sic:1">>} ->
+         decode_sic(<<"urn:xmpp:sic:1">>, IgnoreEls, _el);
+      {<<"port">>, <<"urn:xmpp:sic:1">>} ->
+         decode_sip_port(<<"urn:xmpp:sic:1">>, IgnoreEls, _el);
+      {<<"ip">>, <<"urn:xmpp:sic:0">>} ->
+         decode_sic_ip(<<"urn:xmpp:sic:0">>, IgnoreEls, _el);
+      {<<"ip">>, <<"urn:xmpp:sic:1">>} ->
+         decode_sic_ip(<<"urn:xmpp:sic:1">>, IgnoreEls, _el);
       {<<"x">>, <<"jabber:x:oob">>} ->
          decode_oob_x(<<"jabber:x:oob">>, IgnoreEls, _el);
       {<<"desc">>, <<"jabber:x:oob">>} ->
@@ -1309,6 +1319,11 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) ->
 
 is_known_tag({xmlel, _name, _attrs, _} = _el) ->
     case {_name, get_attr(<<"xmlns">>, _attrs)} of
+      {<<"address">>, <<"urn:xmpp:sic:0">>} -> true;
+      {<<"address">>, <<"urn:xmpp:sic:1">>} -> true;
+      {<<"port">>, <<"urn:xmpp:sic:1">>} -> true;
+      {<<"ip">>, <<"urn:xmpp:sic:0">>} -> true;
+      {<<"ip">>, <<"urn:xmpp:sic:1">>} -> true;
       {<<"x">>, <<"jabber:x:oob">>} -> true;
       {<<"desc">>, <<"jabber:x:oob">>} -> true;
       {<<"url">>, <<"jabber:x:oob">>} -> true;
@@ -2609,7 +2624,9 @@ encode({media, _, _, _} = Media) ->
     encode_media(Media,
                 [{<<"xmlns">>, <<"urn:xmpp:media-element">>}]);
 encode({oob_x, _, _, _} = X) ->
-    encode_oob_x(X, [{<<"xmlns">>, <<"jabber:x:oob">>}]).
+    encode_oob_x(X, [{<<"xmlns">>, <<"jabber:x:oob">>}]);
+encode({sic, _, _, _} = Address) ->
+    encode_sic(Address, []).
 
 get_name({last, _, _}) -> <<"query">>;
 get_name({version, _, _, _}) -> <<"query">>;
@@ -2802,7 +2819,8 @@ get_name({bob_data, _, _, _, _}) -> <<"data">>;
 get_name({xcaptcha, _}) -> <<"captcha">>;
 get_name({media_uri, _, _}) -> <<"uri">>;
 get_name({media, _, _, _}) -> <<"media">>;
-get_name({oob_x, _, _, _}) -> <<"x">>.
+get_name({oob_x, _, _, _}) -> <<"x">>;
+get_name({sic, _, _, _}) -> <<"address">>.
 
 get_ns({last, _, _}) -> <<"jabber:iq:last">>;
 get_ns({version, _, _, _}) -> <<"jabber:iq:version">>;
@@ -3070,7 +3088,8 @@ get_ns({media_uri, _, _}) ->
     <<"urn:xmpp:media-element">>;
 get_ns({media, _, _, _}) ->
     <<"urn:xmpp:media-element">>;
-get_ns({oob_x, _, _, _}) -> <<"jabber:x:oob">>.
+get_ns({oob_x, _, _, _}) -> <<"jabber:x:oob">>;
+get_ns({sic, _, _, Xmlns}) -> Xmlns.
 
 dec_int(Val) -> dec_int(Val, infinity, infinity).
 
@@ -3319,8 +3338,18 @@ pp(xcaptcha, 1) -> [xdata];
 pp(media_uri, 2) -> [type, uri];
 pp(media, 3) -> [height, width, uri];
 pp(oob_x, 3) -> [url, desc, sid];
+pp(sic, 3) -> [ip, port, xmlns];
 pp(_, _) -> no.
 
+enc_ip({0, 0, 0, 0, 0, 65535, A, B}) ->
+    enc_ip({(A bsr 8) band 255, A band 255,
+           (B bsr 8) band 255, B band 255});
+enc_ip(Addr) -> list_to_binary(inet_parse:ntoa(Addr)).
+
+dec_ip(S) ->
+    {ok, Addr} = inet_parse:address(binary_to_list(S)),
+    Addr.
+
 join([], _Sep) -> <<>>;
 join([H | T], Sep) ->
     <<H/binary, << <<Sep, X/binary>>  || X <- T >>/binary>>.
@@ -3365,6 +3394,155 @@ dec_tzo(Val) ->
     M = jlib:binary_to_integer(M1),
     if H >= -12, H =< 12, M >= 0, M < 60 -> {H, M} end.
 
+decode_sic(__TopXMLNS, __IgnoreEls,
+          {xmlel, <<"address">>, _attrs, _els}) ->
+    {Ip, Port} = decode_sic_els(__TopXMLNS, __IgnoreEls,
+                               _els, undefined, undefined),
+    Xmlns = decode_sic_attrs(__TopXMLNS, _attrs, undefined),
+    {sic, Ip, Port, Xmlns}.
+
+decode_sic_els(__TopXMLNS, __IgnoreEls, [], Ip, Port) ->
+    {Ip, Port};
+decode_sic_els(__TopXMLNS, __IgnoreEls,
+              [{xmlel, <<"ip">>, _attrs, _} = _el | _els], Ip,
+              Port) ->
+    case get_attr(<<"xmlns">>, _attrs) of
+      <<"">>
+         when __TopXMLNS == <<"urn:xmpp:sic:1">>;
+              __TopXMLNS == <<"urn:xmpp:sic:0">> ->
+         decode_sic_els(__TopXMLNS, __IgnoreEls, _els,
+                        decode_sic_ip(__TopXMLNS, __IgnoreEls, _el), Port);
+      <<"urn:xmpp:sic:0">> ->
+         decode_sic_els(__TopXMLNS, __IgnoreEls, _els,
+                        decode_sic_ip(<<"urn:xmpp:sic:0">>, __IgnoreEls, _el),
+                        Port);
+      <<"urn:xmpp:sic:1">> ->
+         decode_sic_els(__TopXMLNS, __IgnoreEls, _els,
+                        decode_sic_ip(<<"urn:xmpp:sic:1">>, __IgnoreEls, _el),
+                        Port);
+      _ ->
+         decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip, Port)
+    end;
+decode_sic_els(__TopXMLNS, __IgnoreEls,
+              [{xmlel, <<"port">>, _attrs, _} = _el | _els], Ip,
+              Port) ->
+    case get_attr(<<"xmlns">>, _attrs) of
+      <<"">> when __TopXMLNS == <<"urn:xmpp:sic:1">> ->
+         decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip,
+                        decode_sip_port(__TopXMLNS, __IgnoreEls, _el));
+      <<"urn:xmpp:sic:1">> ->
+         decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip,
+                        decode_sip_port(<<"urn:xmpp:sic:1">>, __IgnoreEls,
+                                        _el));
+      _ ->
+         decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip, Port)
+    end;
+decode_sic_els(__TopXMLNS, __IgnoreEls, [_ | _els], Ip,
+              Port) ->
+    decode_sic_els(__TopXMLNS, __IgnoreEls, _els, Ip, Port).
+
+decode_sic_attrs(__TopXMLNS,
+                [{<<"xmlns">>, _val} | _attrs], _Xmlns) ->
+    decode_sic_attrs(__TopXMLNS, _attrs, _val);
+decode_sic_attrs(__TopXMLNS, [_ | _attrs], Xmlns) ->
+    decode_sic_attrs(__TopXMLNS, _attrs, Xmlns);
+decode_sic_attrs(__TopXMLNS, [], Xmlns) ->
+    decode_sic_attr_xmlns(__TopXMLNS, Xmlns).
+
+encode_sic({sic, Ip, Port, Xmlns}, _xmlns_attrs) ->
+    _els = lists:reverse('encode_sic_$ip'(Ip,
+                                         'encode_sic_$port'(Port, []))),
+    _attrs = encode_sic_attr_xmlns(Xmlns, _xmlns_attrs),
+    {xmlel, <<"address">>, _attrs, _els}.
+
+'encode_sic_$ip'(undefined, _acc) -> _acc;
+'encode_sic_$ip'(Ip, _acc) ->
+    [encode_sic_ip(Ip, []) | _acc].
+
+'encode_sic_$port'(undefined, _acc) -> _acc;
+'encode_sic_$port'(Port, _acc) ->
+    [encode_sip_port(Port, []) | _acc].
+
+decode_sic_attr_xmlns(__TopXMLNS, undefined) ->
+    undefined;
+decode_sic_attr_xmlns(__TopXMLNS, _val) -> _val.
+
+encode_sic_attr_xmlns(undefined, _acc) -> _acc;
+encode_sic_attr_xmlns(_val, _acc) ->
+    [{<<"xmlns">>, _val} | _acc].
+
+decode_sip_port(__TopXMLNS, __IgnoreEls,
+               {xmlel, <<"port">>, _attrs, _els}) ->
+    Cdata = decode_sip_port_els(__TopXMLNS, __IgnoreEls,
+                               _els, <<>>),
+    Cdata.
+
+decode_sip_port_els(__TopXMLNS, __IgnoreEls, [],
+                   Cdata) ->
+    decode_sip_port_cdata(__TopXMLNS, Cdata);
+decode_sip_port_els(__TopXMLNS, __IgnoreEls,
+                   [{xmlcdata, _data} | _els], Cdata) ->
+    decode_sip_port_els(__TopXMLNS, __IgnoreEls, _els,
+                       <<Cdata/binary, _data/binary>>);
+decode_sip_port_els(__TopXMLNS, __IgnoreEls, [_ | _els],
+                   Cdata) ->
+    decode_sip_port_els(__TopXMLNS, __IgnoreEls, _els,
+                       Cdata).
+
+encode_sip_port(Cdata, _xmlns_attrs) ->
+    _els = encode_sip_port_cdata(Cdata, []),
+    _attrs = _xmlns_attrs,
+    {xmlel, <<"port">>, _attrs, _els}.
+
+decode_sip_port_cdata(__TopXMLNS, <<>>) ->
+    erlang:error({xmpp_codec,
+                 {missing_cdata, <<>>, <<"port">>, __TopXMLNS}});
+decode_sip_port_cdata(__TopXMLNS, _val) ->
+    case catch dec_int(_val, 0, 65535) of
+      {'EXIT', _} ->
+         erlang:error({xmpp_codec,
+                       {bad_cdata_value, <<>>, <<"port">>, __TopXMLNS}});
+      _res -> _res
+    end.
+
+encode_sip_port_cdata(_val, _acc) ->
+    [{xmlcdata, enc_int(_val)} | _acc].
+
+decode_sic_ip(__TopXMLNS, __IgnoreEls,
+             {xmlel, <<"ip">>, _attrs, _els}) ->
+    Cdata = decode_sic_ip_els(__TopXMLNS, __IgnoreEls, _els,
+                             <<>>),
+    Cdata.
+
+decode_sic_ip_els(__TopXMLNS, __IgnoreEls, [], Cdata) ->
+    decode_sic_ip_cdata(__TopXMLNS, Cdata);
+decode_sic_ip_els(__TopXMLNS, __IgnoreEls,
+                 [{xmlcdata, _data} | _els], Cdata) ->
+    decode_sic_ip_els(__TopXMLNS, __IgnoreEls, _els,
+                     <<Cdata/binary, _data/binary>>);
+decode_sic_ip_els(__TopXMLNS, __IgnoreEls, [_ | _els],
+                 Cdata) ->
+    decode_sic_ip_els(__TopXMLNS, __IgnoreEls, _els, Cdata).
+
+encode_sic_ip(Cdata, _xmlns_attrs) ->
+    _els = encode_sic_ip_cdata(Cdata, []),
+    _attrs = _xmlns_attrs,
+    {xmlel, <<"ip">>, _attrs, _els}.
+
+decode_sic_ip_cdata(__TopXMLNS, <<>>) ->
+    erlang:error({xmpp_codec,
+                 {missing_cdata, <<>>, <<"ip">>, __TopXMLNS}});
+decode_sic_ip_cdata(__TopXMLNS, _val) ->
+    case catch dec_ip(_val) of
+      {'EXIT', _} ->
+         erlang:error({xmpp_codec,
+                       {bad_cdata_value, <<>>, <<"ip">>, __TopXMLNS}});
+      _res -> _res
+    end.
+
+encode_sic_ip_cdata(_val, _acc) ->
+    [{xmlcdata, enc_ip(_val)} | _acc].
+
 decode_oob_x(__TopXMLNS, __IgnoreEls,
             {xmlel, <<"x">>, _attrs, _els}) ->
     {Desc, Url} = decode_oob_x_els(__TopXMLNS, __IgnoreEls,
index f72e250f25951d6c0275e85a025088c36c7189b1..9cb14282ca1c7aa1c699a44c9386bb38d5f0b106 100644 (file)
                   #ref{name = oob_desc, default = <<"">>,
                        min = 0, max = 1, label = '$desc'}]}).
 
+-xml(sic_ip,
+     #elem{name = <<"ip">>,
+          xmlns = [<<"urn:xmpp:sic:0">>, <<"urn:xmpp:sic:1">>],
+          result = '$cdata',
+          cdata = #cdata{required = true,
+                         dec = {dec_ip, []},
+                         enc = {enc_ip, []}}}).
+
+-xml(sip_port,
+     #elem{name = <<"port">>,
+          xmlns = <<"urn:xmpp:sic:1">>,
+          result = '$cdata',
+          cdata = #cdata{required = true,
+                         dec = {dec_int, [0, 65535]},
+                         enc = {enc_int, []}}}).
+
+-xml(sic,
+     #elem{name = <<"address">>,
+          xmlns = [<<"urn:xmpp:sic:0">>, <<"urn:xmpp:sic:1">>],
+          result = {sic, '$ip', '$port', '$xmlns'},
+          attrs = [#attr{name = <<"xmlns">>}],
+          refs = [#ref{name = sic_ip, min = 0, max = 1, label = '$ip'},
+                  #ref{name = sip_port, min = 0, max = 1, label = '$port'}]}).
+
 dec_tzo(Val) ->
     [H1, M1] = str:tokens(Val, <<":">>),
     H = jlib:binary_to_integer(H1),
@@ -3050,6 +3074,16 @@ join([], _Sep) -> <<>>;
 join([H | T], Sep) ->
     <<H/binary, (<< <<Sep, X/binary>> || X <- T >>)/binary>>.
 
+dec_ip(S) ->
+    {ok, Addr} = inet_parse:address(binary_to_list(S)),
+    Addr.
+
+enc_ip({0,0,0,0,0,16#ffff,A,B}) ->
+    enc_ip({(A bsr 8) band 16#ff, A band 16#ff,
+           (B bsr 8) band 16#ff, B band 16#ff});
+enc_ip(Addr) ->
+    list_to_binary(inet_parse:ntoa(Addr)).
+
 %% Local Variables:
 %% mode: erlang
 %% End: