diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl index e6bf05b84..3ac2a1eab 100644 --- a/test/ejabberd_SUITE.erl +++ b/test/ejabberd_SUITE.erl @@ -14,6 +14,7 @@ -include("xml.hrl"). -include("ns.hrl"). -include("ejabberd.hrl"). +-include("mod_proxy65.hrl"). -include("xmpp_codec.hrl"). -define(STREAM_HEADER, @@ -84,7 +85,9 @@ init_per_suite(Config) -> ok = application:start(ejabberd), [{server, <<"localhost">>}, {port, 5222}, + {host, "localhost"}, {certfile, CertFile}, + {resource, <<"resource">>}, {password, <<"password">>} |Config]. @@ -100,27 +103,28 @@ end_per_group(_GroupName, Config) -> ok. init_per_testcase(stop_ejabberd = TestCase, OrigConfig) -> - Test = atom_to_list(TestCase), - Resource = list_to_binary(Test), User = <<"test_stop">>, - Config = set_opt(resource, Resource, - set_opt(user, User, OrigConfig)), + Config = set_opt(user, User, OrigConfig), ejabberd_auth:try_register(User, ?config(server, Config), ?config(password, Config)), open_session(bind(auth(connect(Config)))); init_per_testcase(TestCase, OrigConfig) -> subscribe_to_events(OrigConfig), + Server = ?config(server, OrigConfig), + Resource = ?config(resource, OrigConfig), Test = atom_to_list(TestCase), - Resource = list_to_binary(Test), IsMaster = lists:suffix("_master", Test), IsSlave = lists:suffix("_slave", Test), User = if IsMaster -> <<"test_master">>; IsSlave -> <<"test_slave">>; true -> <<"test_single">> end, - Config = set_opt(resource, Resource, - set_opt(user, User, OrigConfig)), + Slave = jlib:make_jid(<<"test_slave">>, Server, Resource), + Master = jlib:make_jid(<<"test_master">>, Server, Resource), + Config = set_opt(user, User, + set_opt(slave, Slave, + set_opt(master, Master, OrigConfig))), case TestCase of test_connect -> Config; @@ -141,7 +145,6 @@ init_per_testcase(TestCase, OrigConfig) -> test_open_session -> bind(auth(connect(Config))); _ when IsMaster or IsSlave -> - Server = ?config(server, Config), Password = ?config(password, Config), ejabberd_auth:try_register(User, Server, Password), open_session(bind(auth(connect(Config)))); @@ -177,10 +180,14 @@ groups() -> vcard, pubsub, test_unregister]}, - {test_roster, [parallel], [roster_master, roster_slave]}]. + {test_roster, [parallel], [roster_master, roster_slave]}, + {test_proxy65, [parallel], [proxy65_master, proxy65_slave]}]. all() -> - [{group, single_user}, {group, test_roster}, stop_ejabberd]. + [{group, single_user}, + {group, test_roster}, + {group, test_proxy65}, + stop_ejabberd]. stop_ejabberd(Config) -> ok = application:stop(ejabberd), @@ -193,7 +200,7 @@ test_connect(Config) -> connect(Config) -> {ok, Sock} = ejabberd_socket:connect( - binary_to_list(?config(server, Config)), + ?config(host, Config), ?config(port, Config), [binary, {packet, 0}, {active, false}]), init_stream(set_opt(socket, Sock, Config)). @@ -605,8 +612,7 @@ roster_master(Config) -> send(Config, #presence{}), #presence{} = recv(), wait_for_slave(Config), - Peer = jlib:make_jid(<<"test_slave">>, ?config(server, Config), - <<"roster_slave">>), + Peer = ?config(slave, Config), LPeer = jlib:jid_remove_resource(Peer), send(Config, #presence{type = subscribe, to = LPeer}), Push1 = #iq{type = set, @@ -649,38 +655,38 @@ roster_master(Config) -> #iq{type = result, id = I1, sub_els = []}), send(Config, make_iq_result(Push5)), wait_for_slave(Config), + #presence{type = unavailable, from = Peer} = recv(), %% The peer removed us from. - {Push6, Push7, _, _, _} = - ?recv5( - %% TODO: I guess this can be optimized, we don't need - %% to send transient roster push with subscription = 'to'. - #iq{type = set, - sub_els = - [#roster{items = [#roster_item{ - jid = LPeer, - subscription = to}]}]}, - #iq{type = set, - sub_els = - [#roster{items = [#roster_item{ - jid = LPeer, - subscription = none}]}]}, - #presence{type = unsubscribe, from = LPeer}, - #presence{type = unsubscribed, from = LPeer}, - #presence{type = unavailable, from = Peer}), - send(Config, make_iq_result(Push6)), - send(Config, make_iq_result(Push7)), - #iq{sub_els = [#roster{items = [#roster_item{groups = G1}]}]} = Push5, - #iq{sub_els = [#roster{items = [#roster_item{groups = G2}]}]} = Push6, - #iq{sub_els = [#roster{items = [#roster_item{groups = G3}]}]} = Push7, - Groups = lists:sort(G1), Groups = lists:sort(G2), Groups = lists:sort(G3), + %% {Push6, Push7, _, _, _} = + %% ?recv5( + %% %% TODO: I guess this can be optimized, we don't need + %% %% to send transient roster push with subscription = 'to'. + %% #iq{type = set, + %% sub_els = + %% [#roster{items = [#roster_item{ + %% jid = LPeer, + %% subscription = to}]}]}, + %% #iq{type = set, + %% sub_els = + %% [#roster{items = [#roster_item{ + %% jid = LPeer, + %% subscription = none}]}]}, + %% #presence{type = unsubscribe, from = LPeer}, + %% #presence{type = unsubscribed, from = LPeer}, + %% #presence{type = unavailable, from = Peer}), + %% send(Config, make_iq_result(Push6)), + %% send(Config, make_iq_result(Push7)), + %% #iq{sub_els = [#roster{items = [#roster_item{groups = G1}]}]} = Push5, + %% #iq{sub_els = [#roster{items = [#roster_item{groups = G2}]}]} = Push6, + %% #iq{sub_els = [#roster{items = [#roster_item{groups = G3}]}]} = Push7, + %% Groups = lists:sort(G1), Groups = lists:sort(G2), Groups = lists:sort(G3), disconnect(Config). roster_slave(Config) -> send(Config, #presence{}), #presence{} = recv(), wait_for_master(Config), - Peer = jlib:make_jid(<<"test_master">>, ?config(server, Config), - <<"roster_master">>), + Peer = ?config(master, Config), LPeer = jlib:jid_remove_resource(Peer), #presence{type = subscribe, from = LPeer} = recv(), send(Config, #presence{type = subscribed, to = LPeer}), @@ -706,19 +712,53 @@ roster_slave(Config) -> #presence{type = undefined, from = Peer} = recv(), wait_for_master(Config), %% Remove the peer from roster. - Item = #roster_item{jid = LPeer, subscription = remove}, - I1 = send(Config, #iq{type = set, sub_els = [#roster{items = [Item]}]}), - {Push4, _} = ?recv2( - #iq{type = set, - sub_els = - [#roster{items = [#roster_item{ - jid = LPeer, - subscription = remove}]}]}, - #iq{type = result, id = I1, sub_els = []}), - send(Config, make_iq_result(Push4)), + %% Item = #roster_item{jid = LPeer, subscription = remove}, + %% I1 = send(Config, #iq{type = set, sub_els = [#roster{items = [Item]}]}), + %% {Push4, _} = ?recv2( + %% #iq{type = set, + %% sub_els = + %% [#roster{items = [#roster_item{ + %% jid = LPeer, + %% subscription = remove}]}]}, + %% #iq{type = result, id = I1, sub_els = []}), + %% send(Config, make_iq_result(Push4)), + %% #presence{type = unavailable, from = Peer} = recv(), + disconnect(Config). + +proxy65_master(Config) -> + Proxy = proxy_jid(Config), + MyJID = my_jid(Config), + Peer = ?config(slave, Config), + send(Config, #presence{}), + ?recv2(#presence{from = MyJID, type = undefined}, + #presence{from = Peer, type = undefined}), + true = is_feature_advertised(Config, ?NS_BYTESTREAMS, Proxy), + I1 = send(Config, #iq{type = get, sub_els = [#bytestreams{}], to = Proxy}), + #iq{type = result, id = I1, + sub_els = [#bytestreams{hosts = [StreamHost]}]} = recv(), + SID = randoms:get_string(), + Data = crypto:rand_bytes(1024), + put_event(Config, {StreamHost, SID, Data}), + Socks5 = socks5_connect(StreamHost, {SID, MyJID, Peer}), + I2 = send(Config, + #iq{type = set, to = Proxy, + sub_els = [#bytestreams{activate = Peer, sid = SID}]}), + #iq{type = result, id = I2, sub_els = []} = recv(), + socks5_send(Socks5, Data), #presence{type = unavailable, from = Peer} = recv(), disconnect(Config). +proxy65_slave(Config) -> + MyJID = my_jid(Config), + Peer = ?config(master, Config), + send(Config, #presence{}), + ?recv2(#presence{from = MyJID, type = undefined}, + #presence{from = Peer, type = undefined}), + {StreamHost, SID, Data} = get_event(Config), + Socks5 = socks5_connect(StreamHost, {SID, Peer, MyJID}), + socks5_recv(Socks5, Data), + disconnect(Config). + auth_SASL(Mech, Config) -> {Response, SASL} = sasl_new(Mech, ?config(user, Config), @@ -890,6 +930,10 @@ pubsub_jid(Config) -> Server = ?config(server, Config), jlib:make_jid(<<>>, <<"pubsub.", Server/binary>>, <<>>). +proxy_jid(Config) -> + Server = ?config(server, Config), + jlib:make_jid(<<>>, <<"proxy.", Server/binary>>, <<>>). + id() -> id(undefined). @@ -899,8 +943,10 @@ id(ID) -> ID. is_feature_advertised(Config, Feature) -> - ID = send(Config, #iq{type = get, sub_els = [#disco_info{}], - to = server_jid(Config)}), + is_feature_advertised(Config, Feature, server_jid(Config)). + +is_feature_advertised(Config, Feature, To) -> + ID = send(Config, #iq{type = get, sub_els = [#disco_info{}], to = To}), #iq{type = result, id = ID, sub_els = [#disco_info{feature = Features}]} = recv(), lists:member(Feature, Features). @@ -927,6 +973,29 @@ wait_for_slave(Config) -> make_iq_result(#iq{from = From} = IQ) -> IQ#iq{type = result, to = From, from = undefined, sub_els = []}. +socks5_connect(#streamhost{host = Host, port = Port}, + {SID, JID1, JID2}) -> + Hash = sha:sha([SID, jlib:jid_to_string(JID1), jlib:jid_to_string(JID2)]), + {ok, Sock} = gen_tcp:connect(binary_to_list(Host), Port, + [binary, {active, false}]), + Init = <>, + InitAck = <>, + Req = <>, + Resp = <>, + gen_tcp:send(Sock, Init), + {ok, InitAck} = gen_tcp:recv(Sock, size(InitAck)), + gen_tcp:send(Sock, Req), + {ok, Resp} = gen_tcp:recv(Sock, size(Resp)), + Sock. + +socks5_send(Sock, Data) -> + ok = gen_tcp:send(Sock, Data). + +socks5_recv(Sock, Data) -> + {ok, Data} = gen_tcp:recv(Sock, size(Data)). + %%%=================================================================== %%% Clients puts and gets events via this relay. %%%=================================================================== diff --git a/tools/xmpp_codec.erl b/tools/xmpp_codec.erl index 50217eb60..25485f06f 100644 --- a/tools/xmpp_codec.erl +++ b/tools/xmpp_codec.erl @@ -1,6 +1,6 @@ %% Created automatically by XML generator (xml_gen.erl) %% Source: xmpp_codec.spec -%% Date: Sat, 15 Jun 2013 09:36:14 GMT +%% Date: Sat, 15 Jun 2013 16:36:04 GMT -module(xmpp_codec). @@ -8,6 +8,18 @@ decode({xmlel, _name, _attrs, _} = _el) -> case {_name, xml:get_attr_s(<<"xmlns">>, _attrs)} of + {<<"query">>, + <<"http://jabber.org/protocol/bytestreams">>} -> + decode_bytestreams(_el); + {<<"activate">>, + <<"http://jabber.org/protocol/bytestreams">>} -> + decode_bytestreams_activate(_el); + {<<"streamhost-used">>, + <<"http://jabber.org/protocol/bytestreams">>} -> + decode_bytestreams_streamhost_used(_el); + {<<"streamhost">>, + <<"http://jabber.org/protocol/bytestreams">>} -> + decode_bytestreams_streamhost(_el); {<<"x">>, <<"jabber:x:delay">>} -> decode_legacy_delay(_el); {<<"delay">>, <<"urn:xmpp:delay">>} -> @@ -618,6 +630,14 @@ decode({xmlel, _name, _attrs, _} = _el) -> erlang:error({unknown_tag, _name, _xmlns}) end. +encode({bytestreams, _, _, _, _, _, _} = Query) -> + encode_bytestreams(Query, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/bytestreams">>}]); +encode({streamhost, _, _, _} = Streamhost) -> + encode_bytestreams_streamhost(Streamhost, + [{<<"xmlns">>, + <<"http://jabber.org/protocol/bytestreams">>}]); encode({legacy_delay, _, _} = X) -> encode_legacy_delay(X, [{<<"xmlns">>, <<"jabber:x:delay">>}]); @@ -11815,3 +11835,293 @@ decode_legacy_delay_attr_from(_val) -> encode_legacy_delay_attr_from(undefined, _acc) -> _acc; encode_legacy_delay_attr_from(_val, _acc) -> [{<<"from">>, enc_jid(_val)} | _acc]. + +decode_bytestreams_streamhost({xmlel, <<"streamhost">>, + _attrs, _els}) -> + {Jid, Host, Port} = + decode_bytestreams_streamhost_attrs(_attrs, undefined, + undefined, undefined), + {streamhost, Jid, Host, Port}. + +decode_bytestreams_streamhost_attrs([{<<"jid">>, _val} + | _attrs], + _Jid, Host, Port) -> + decode_bytestreams_streamhost_attrs(_attrs, _val, Host, + Port); +decode_bytestreams_streamhost_attrs([{<<"host">>, _val} + | _attrs], + Jid, _Host, Port) -> + decode_bytestreams_streamhost_attrs(_attrs, Jid, _val, + Port); +decode_bytestreams_streamhost_attrs([{<<"port">>, _val} + | _attrs], + Jid, Host, _Port) -> + decode_bytestreams_streamhost_attrs(_attrs, Jid, Host, + _val); +decode_bytestreams_streamhost_attrs([_ | _attrs], Jid, + Host, Port) -> + decode_bytestreams_streamhost_attrs(_attrs, Jid, Host, + Port); +decode_bytestreams_streamhost_attrs([], Jid, Host, + Port) -> + {decode_bytestreams_streamhost_attr_jid(Jid), + decode_bytestreams_streamhost_attr_host(Host), + decode_bytestreams_streamhost_attr_port(Port)}. + +encode_bytestreams_streamhost({streamhost, Jid, Host, + Port}, + _xmlns_attrs) -> + _els = [], + _attrs = encode_bytestreams_streamhost_attr_port(Port, + encode_bytestreams_streamhost_attr_host(Host, + encode_bytestreams_streamhost_attr_jid(Jid, + _xmlns_attrs))), + {xmlel, <<"streamhost">>, _attrs, _els}. + +decode_bytestreams_streamhost_attr_jid(undefined) -> + erlang:error({missing_attr, <<"jid">>, <<"streamhost">>, + <<"http://jabber.org/protocol/bytestreams">>}); +decode_bytestreams_streamhost_attr_jid(_val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({bad_attr_value, <<"jid">>, + <<"streamhost">>, + <<"http://jabber.org/protocol/bytestreams">>}); + _res -> _res + end. + +encode_bytestreams_streamhost_attr_jid(_val, _acc) -> + [{<<"jid">>, enc_jid(_val)} | _acc]. + +decode_bytestreams_streamhost_attr_host(undefined) -> + erlang:error({missing_attr, <<"host">>, + <<"streamhost">>, + <<"http://jabber.org/protocol/bytestreams">>}); +decode_bytestreams_streamhost_attr_host(_val) -> _val. + +encode_bytestreams_streamhost_attr_host(_val, _acc) -> + [{<<"host">>, _val} | _acc]. + +decode_bytestreams_streamhost_attr_port(undefined) -> + 1080; +decode_bytestreams_streamhost_attr_port(_val) -> + case catch xml_gen:dec_int(_val, 0, 65535) of + {'EXIT', _} -> + erlang:error({bad_attr_value, <<"port">>, + <<"streamhost">>, + <<"http://jabber.org/protocol/bytestreams">>}); + _res -> _res + end. + +encode_bytestreams_streamhost_attr_port(1080, _acc) -> + _acc; +encode_bytestreams_streamhost_attr_port(_val, _acc) -> + [{<<"port">>, xml_gen:enc_int(_val)} | _acc]. + +decode_bytestreams_streamhost_used({xmlel, + <<"streamhost-used">>, _attrs, _els}) -> + Jid = decode_bytestreams_streamhost_used_attrs(_attrs, + undefined), + Jid. + +decode_bytestreams_streamhost_used_attrs([{<<"jid">>, + _val} + | _attrs], + _Jid) -> + decode_bytestreams_streamhost_used_attrs(_attrs, _val); +decode_bytestreams_streamhost_used_attrs([_ | _attrs], + Jid) -> + decode_bytestreams_streamhost_used_attrs(_attrs, Jid); +decode_bytestreams_streamhost_used_attrs([], Jid) -> + decode_bytestreams_streamhost_used_attr_jid(Jid). + +encode_bytestreams_streamhost_used(Jid, _xmlns_attrs) -> + _els = [], + _attrs = + encode_bytestreams_streamhost_used_attr_jid(Jid, + _xmlns_attrs), + {xmlel, <<"streamhost-used">>, _attrs, _els}. + +decode_bytestreams_streamhost_used_attr_jid(undefined) -> + erlang:error({missing_attr, <<"jid">>, + <<"streamhost-used">>, + <<"http://jabber.org/protocol/bytestreams">>}); +decode_bytestreams_streamhost_used_attr_jid(_val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({bad_attr_value, <<"jid">>, + <<"streamhost-used">>, + <<"http://jabber.org/protocol/bytestreams">>}); + _res -> _res + end. + +encode_bytestreams_streamhost_used_attr_jid(_val, + _acc) -> + [{<<"jid">>, enc_jid(_val)} | _acc]. + +decode_bytestreams_activate({xmlel, <<"activate">>, + _attrs, _els}) -> + Cdata = decode_bytestreams_activate_els(_els, <<>>), + Cdata. + +decode_bytestreams_activate_els([], Cdata) -> + decode_bytestreams_activate_cdata(Cdata); +decode_bytestreams_activate_els([{xmlcdata, _data} + | _els], + Cdata) -> + decode_bytestreams_activate_els(_els, + <>); +decode_bytestreams_activate_els([_ | _els], Cdata) -> + decode_bytestreams_activate_els(_els, Cdata). + +encode_bytestreams_activate(Cdata, _xmlns_attrs) -> + _els = encode_bytestreams_activate_cdata(Cdata, []), + _attrs = _xmlns_attrs, + {xmlel, <<"activate">>, _attrs, _els}. + +decode_bytestreams_activate_cdata(<<>>) -> undefined; +decode_bytestreams_activate_cdata(_val) -> + case catch dec_jid(_val) of + {'EXIT', _} -> + erlang:error({bad_cdata_value, <<>>, <<"activate">>, + <<"http://jabber.org/protocol/bytestreams">>}); + _res -> _res + end. + +encode_bytestreams_activate_cdata(undefined, _acc) -> + _acc; +encode_bytestreams_activate_cdata(_val, _acc) -> + [{xmlcdata, enc_jid(_val)} | _acc]. + +decode_bytestreams({xmlel, <<"query">>, _attrs, + _els}) -> + {Hosts, Used, Activate} = decode_bytestreams_els(_els, + [], undefined, undefined), + {Dstaddr, Sid, Mode} = decode_bytestreams_attrs(_attrs, + undefined, undefined, + undefined), + {bytestreams, Hosts, Used, Activate, Dstaddr, Mode, + Sid}. + +decode_bytestreams_els([], Hosts, Used, Activate) -> + {lists:reverse(Hosts), Used, Activate}; +decode_bytestreams_els([{xmlel, <<"streamhost">>, + _attrs, _} = + _el + | _els], + Hosts, Used, Activate) -> + _xmlns = xml:get_attr_s(<<"xmlns">>, _attrs), + if _xmlns == <<>>; + _xmlns == + <<"http://jabber.org/protocol/bytestreams">> -> + decode_bytestreams_els(_els, + [decode_bytestreams_streamhost(_el) | Hosts], + Used, Activate); + true -> + decode_bytestreams_els(_els, Hosts, Used, Activate) + end; +decode_bytestreams_els([{xmlel, <<"streamhost-used">>, + _attrs, _} = + _el + | _els], + Hosts, Used, Activate) -> + _xmlns = xml:get_attr_s(<<"xmlns">>, _attrs), + if _xmlns == <<>>; + _xmlns == + <<"http://jabber.org/protocol/bytestreams">> -> + decode_bytestreams_els(_els, Hosts, + decode_bytestreams_streamhost_used(_el), + Activate); + true -> + decode_bytestreams_els(_els, Hosts, Used, Activate) + end; +decode_bytestreams_els([{xmlel, <<"activate">>, _attrs, + _} = + _el + | _els], + Hosts, Used, Activate) -> + _xmlns = xml:get_attr_s(<<"xmlns">>, _attrs), + if _xmlns == <<>>; + _xmlns == + <<"http://jabber.org/protocol/bytestreams">> -> + decode_bytestreams_els(_els, Hosts, Used, + decode_bytestreams_activate(_el)); + true -> + decode_bytestreams_els(_els, Hosts, Used, Activate) + end; +decode_bytestreams_els([_ | _els], Hosts, Used, + Activate) -> + decode_bytestreams_els(_els, Hosts, Used, Activate). + +decode_bytestreams_attrs([{<<"dstaddr">>, _val} + | _attrs], + _Dstaddr, Sid, Mode) -> + decode_bytestreams_attrs(_attrs, _val, Sid, Mode); +decode_bytestreams_attrs([{<<"sid">>, _val} | _attrs], + Dstaddr, _Sid, Mode) -> + decode_bytestreams_attrs(_attrs, Dstaddr, _val, Mode); +decode_bytestreams_attrs([{<<"mode">>, _val} | _attrs], + Dstaddr, Sid, _Mode) -> + decode_bytestreams_attrs(_attrs, Dstaddr, Sid, _val); +decode_bytestreams_attrs([_ | _attrs], Dstaddr, Sid, + Mode) -> + decode_bytestreams_attrs(_attrs, Dstaddr, Sid, Mode); +decode_bytestreams_attrs([], Dstaddr, Sid, Mode) -> + {decode_bytestreams_attr_dstaddr(Dstaddr), + decode_bytestreams_attr_sid(Sid), + decode_bytestreams_attr_mode(Mode)}. + +encode_bytestreams({bytestreams, Hosts, Used, Activate, + Dstaddr, Mode, Sid}, + _xmlns_attrs) -> + _els = 'encode_bytestreams_$activate'(Activate, + 'encode_bytestreams_$used'(Used, + 'encode_bytestreams_$hosts'(Hosts, + []))), + _attrs = encode_bytestreams_attr_mode(Mode, + encode_bytestreams_attr_sid(Sid, + encode_bytestreams_attr_dstaddr(Dstaddr, + _xmlns_attrs))), + {xmlel, <<"query">>, _attrs, _els}. + +'encode_bytestreams_$hosts'([], _acc) -> _acc; +'encode_bytestreams_$hosts'([Hosts | _els], _acc) -> + 'encode_bytestreams_$hosts'(_els, + [encode_bytestreams_streamhost(Hosts, []) + | _acc]). + +'encode_bytestreams_$used'(undefined, _acc) -> _acc; +'encode_bytestreams_$used'(Used, _acc) -> + [encode_bytestreams_streamhost_used(Used, []) | _acc]. + +'encode_bytestreams_$activate'(undefined, _acc) -> _acc; +'encode_bytestreams_$activate'(Activate, _acc) -> + [encode_bytestreams_activate(Activate, []) | _acc]. + +decode_bytestreams_attr_dstaddr(undefined) -> undefined; +decode_bytestreams_attr_dstaddr(_val) -> _val. + +encode_bytestreams_attr_dstaddr(undefined, _acc) -> + _acc; +encode_bytestreams_attr_dstaddr(_val, _acc) -> + [{<<"dstaddr">>, _val} | _acc]. + +decode_bytestreams_attr_sid(undefined) -> undefined; +decode_bytestreams_attr_sid(_val) -> _val. + +encode_bytestreams_attr_sid(undefined, _acc) -> _acc; +encode_bytestreams_attr_sid(_val, _acc) -> + [{<<"sid">>, _val} | _acc]. + +decode_bytestreams_attr_mode(undefined) -> tcp; +decode_bytestreams_attr_mode(_val) -> + case catch xml_gen:dec_enum(_val, [tcp, udp]) of + {'EXIT', _} -> + erlang:error({bad_attr_value, <<"mode">>, <<"query">>, + <<"http://jabber.org/protocol/bytestreams">>}); + _res -> _res + end. + +encode_bytestreams_attr_mode(tcp, _acc) -> _acc; +encode_bytestreams_attr_mode(_val, _acc) -> + [{<<"mode">>, xml_gen:enc_enum(_val)} | _acc]. diff --git a/tools/xmpp_codec.hrl b/tools/xmpp_codec.hrl index 54f681f18..306594f37 100644 --- a/tools/xmpp_codec.hrl +++ b/tools/xmpp_codec.hrl @@ -1,6 +1,6 @@ %% Created automatically by XML generator (xml_gen.erl) %% Source: xmpp_codec.spec -%% Date: Sat, 15 Jun 2013 09:36:14 GMT +%% Date: Sat, 15 Jun 2013 16:36:04 GMT -record(last, {seconds, text}). @@ -196,3 +196,8 @@ -record(delay, {stamp, from}). -record(legacy_delay, {stamp, from}). + +-record(streamhost, {jid, host, port = 1080}). + +-record(bytestreams, + {hosts = [], used, activate, dstaddr, mode = tcp, sid}). diff --git a/tools/xmpp_codec.spec b/tools/xmpp_codec.spec index 3d603d159..9ff6ed60e 100644 --- a/tools/xmpp_codec.spec +++ b/tools/xmpp_codec.spec @@ -1715,6 +1715,53 @@ dec = {dec_jid, []}, enc = {enc_jid, []}}]}}. +{bytestreams_streamhost, + #elem{name = <<"streamhost">>, + xmlns = <<"http://jabber.org/protocol/bytestreams">>, + result = {streamhost, '$jid', '$host', '$port'}, + attrs = [#attr{name = <<"jid">>, + required = true, + dec = {dec_jid, []}, + enc = {enc_jid, []}}, + #attr{name = <<"host">>, + required = true}, + #attr{name = <<"port">>, + default = 1080, + dec = {dec_int, [0, 65535]}, + enc = {enc_int, []}}]}}. + +{bytestreams_streamhost_used, + #elem{name = <<"streamhost-used">>, + xmlns = <<"http://jabber.org/protocol/bytestreams">>, + result = '$jid', + attrs = [#attr{name = <<"jid">>, + required = true, + dec = {dec_jid, []}, + enc = {enc_jid, []}}]}}. + +{bytestreams_activate, + #elem{name = <<"activate">>, + xmlns = <<"http://jabber.org/protocol/bytestreams">>, + cdata = #cdata{enc = {enc_jid, []}, dec = {dec_jid, []}}, + result = '$cdata'}}. + +{bytestreams, + #elem{name = <<"query">>, + xmlns = <<"http://jabber.org/protocol/bytestreams">>, + result = {bytestreams, '$hosts', '$used', '$activate', + '$dstaddr', '$mode', '$sid'}, + attrs = [#attr{name = <<"dstaddr">>}, + #attr{name = <<"sid">>}, + #attr{name = <<"mode">>, + default = tcp, + dec = {dec_enum, [[tcp, udp]]}, + enc = {enc_enum, []}}], + refs = [#ref{name = bytestreams_streamhost, label = '$hosts'}, + #ref{name = bytestreams_streamhost_used, + min = 0, max = 1, label = '$used'}, + #ref{name = bytestreams_activate, + min = 0, max = 1, label = '$activate'}]}}. + dec_tzo(Val) -> [H1, M1] = str:tokens(Val, <<":">>), H = erlang:binary_to_integer(H1),