25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-24 16:23:40 +01:00

exmpp fixes in http_bind (thanks to Karim Gemayel)

SVN Revision: 2929
This commit is contained in:
Badlop 2010-01-27 18:53:27 +00:00
parent f20d2bb2ff
commit e98df7acb1

View File

@ -37,9 +37,7 @@
-include("ejabberd.hrl"). -include("ejabberd.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
-include("ejabberd_http.hrl"). -include("ejabberd_http.hrl").
-include_lib("exmpp/include/exmpp.hrl").
%% TODO: Use exmpp library instead of including this
-define(NS_STREAM, "http://etherx.jabber.org/streams").
-record(http_bind, {id, pid, to, hold, wait, version}). -record(http_bind, {id, pid, to, hold, wait, version}).
@ -90,9 +88,6 @@
-endif. -endif.
-define(BOSH_VERSION, "1.8"). -define(BOSH_VERSION, "1.8").
-define(NS_CLIENT, "jabber:client").
-define(NS_BOSH, "urn:xmpp:xbosh").
-define(NS_HTTP_BIND, "http://jabber.org/protocol/httpbind").
-define(MAX_REQUESTS, 2). % number of simultaneous requests -define(MAX_REQUESTS, 2). % number of simultaneous requests
-define(MIN_POLLING, 2000000). % don't poll faster than that or we will -define(MIN_POLLING, 2000000). % don't poll faster than that or we will
@ -183,7 +178,7 @@ process_request(Data, IP) ->
?ERROR_MSG("Session not created (Improper addressing)", []), ?ERROR_MSG("Session not created (Improper addressing)", []),
{200, ?HEADER, "<body type='terminate' " {200, ?HEADER, "<body type='terminate' "
"condition='improper-addressing' " "condition='improper-addressing' "
"xmlns='" ++ ?NS_HTTP_BIND ++ "'/>"}; "xmlns='" ++ ?NS_HTTP_BIND_s ++ "'/>"};
XmppDomain -> XmppDomain ->
%% create new session %% create new session
Sid = sha:sha(term_to_binary({now(), make_ref()})), Sid = sha:sha(term_to_binary({now(), make_ref()})),
@ -191,7 +186,7 @@ process_request(Data, IP) ->
{error, _} -> {error, _} ->
{200, ?HEADER, "<body type='terminate' " {200, ?HEADER, "<body type='terminate' "
"condition='internal-server-error' " "condition='internal-server-error' "
"xmlns='" ++ ?NS_HTTP_BIND ++ "'>BOSH module not started</body>"}; "xmlns='" ++ ?NS_HTTP_BIND_s ++ "'>BOSH module not started</body>"};
{ok, Pid} -> {ok, Pid} ->
handle_session_start( handle_session_start(
Pid, XmppDomain, Sid, Rid, Attrs, Pid, XmppDomain, Sid, Rid, Attrs,
@ -224,7 +219,7 @@ process_request(Data, IP) ->
gen_fsm:sync_send_all_state_event(FsmRef, {stop, close}), gen_fsm:sync_send_all_state_event(FsmRef, {stop, close}),
{200, ?HEADER, "<body type='terminate' " {200, ?HEADER, "<body type='terminate' "
"condition='undefined-condition' " "condition='undefined-condition' "
"xmlns='" ++ ?NS_HTTP_BIND ++ "'>Request Too Large</body>"} "xmlns='" ++ ?NS_HTTP_BIND_s ++ "'>Request Too Large</body>"}
end; end;
_ -> _ ->
?DEBUG("Received bad request: ~p", [Data]), ?DEBUG("Received bad request: ~p", [Data]),
@ -698,16 +693,16 @@ process_http_put(#http_put{rid = Rid, attrs = Attrs, payload = Payload,
C2SPid, C2SPid,
{xmlstreamstart, "stream:stream", {xmlstreamstart, "stream:stream",
[{"to", To}, [{"to", To},
{"xmlns", ?NS_CLIENT}, {"xmlns", ?NS_JABBER_CLIENT_s},
{"xmlns:stream", ?NS_STREAM}]}); {"xmlns:stream", ?NS_XMPP_s}]});
{To, Version} -> {To, Version} ->
gen_fsm:send_event( gen_fsm:send_event(
C2SPid, C2SPid,
{xmlstreamstart, "stream:stream", {xmlstreamstart, "stream:stream",
[{"to", To}, [{"to", To},
{"xmlns", ?NS_CLIENT}, {"xmlns", ?NS_JABBER_CLIENT_s},
{"version", Version}, {"version", Version},
{"xmlns:stream", ?NS_STREAM}]}); {"xmlns:stream", ?NS_XMPP_s}]});
_ -> _ ->
ok ok
end, end,
@ -776,12 +771,12 @@ handle_http_put(Sid, Rid, Attrs, Payload, PayloadSize, StreamStart, IP) ->
%{200, ?HEADER, %{200, ?HEADER,
% xml:element_to_string( % xml:element_to_string(
% {xmlelement, "body", % {xmlelement, "body",
% [{"xmlns", ?NS_HTTP_BIND}, % [{"xmlns", ?NS_HTTP_BIND_s},
% {"type", "error"}], []})}; % {"type", "error"}], []})};
handle_http_put(Sid, Rid, Attrs, Payload, PayloadSize, handle_http_put(Sid, Rid, Attrs, Payload, PayloadSize,
StreamStart, IP); StreamStart, IP);
{buffered, _Sess} -> {buffered, _Sess} ->
{200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND_s++"'/>"};
{ok, Sess} -> {ok, Sess} ->
prepare_response(Sess, Rid, Attrs, StreamStart) prepare_response(Sess, Rid, Attrs, StreamStart)
end. end.
@ -812,24 +807,51 @@ handle_http_put_error(Reason, #http_bind{pid=FsmRef, version=Version})
not_exists -> not_exists ->
{200, ?HEADER, {200, ?HEADER,
xml:element_to_string( xml:element_to_string(
{xmlelement, "body", #xmlel{name = 'body',
[{"xmlns", ?NS_HTTP_BIND}, ns = ?NS_HTTP_BIND_s,
{"type", "terminate"}, attrs = [
{"condition", "item-not-found"}], []})}; #xmlattr{name = 'type',
ns = ?NS_HTTP_BIND_s,
value = 'terminate'
},
#xmlattr{name = 'type',
ns = ?NS_HTTP_BIND_s,
value = 'item-not-found'
}
]
})};
bad_key -> bad_key ->
{200, ?HEADER, {200, ?HEADER,
xml:element_to_string( xml:element_to_string(
{xmlelement, "body", #xmlel{name = 'body',
[{"xmlns", ?NS_HTTP_BIND}, ns = ?NS_HTTP_BIND_s,
{"type", "terminate"}, attrs = [
{"condition", "item-not-found"}], []})}; #xmlattr{name = 'type',
ns = ?NS_HTTP_BIND_s,
value = 'terminate'
},
#xmlattr{name = 'type',
ns = ?NS_HTTP_BIND_s,
value = 'item-not-found'
}
]
})};
polling_too_frequently -> polling_too_frequently ->
{200, ?HEADER, {200, ?HEADER,
xml:element_to_string( xml:element_to_string(
{xmlelement, "body", #xmlel{name = 'body',
[{"xmlns", ?NS_HTTP_BIND}, ns = ?NS_HTTP_BIND_s,
{"type", "terminate"}, attrs = [
{"condition", "policy-violation"}], []})} #xmlattr{name = 'type',
ns = ?NS_HTTP_BIND_s,
value = 'terminate'
},
#xmlattr{name = 'type',
ns = ?NS_HTTP_BIND_s,
value = 'policy-violation'
}
]
})}
end; end;
handle_http_put_error(Reason, #http_bind{pid=FsmRef}) -> handle_http_put_error(Reason, #http_bind{pid=FsmRef}) ->
gen_fsm:sync_send_all_state_event(FsmRef,{stop, {put_error_no_version, Reason}}), gen_fsm:sync_send_all_state_event(FsmRef,{stop, {put_error_no_version, Reason}}),
@ -893,11 +915,11 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold, to=To}=Sess,
%% actually it would be better if we could completely %% actually it would be better if we could completely
%% cancel this request, but then we would have to hack %% cancel this request, but then we would have to hack
%% ejabberd_http and I'm too lazy now %% ejabberd_http and I'm too lazy now
{200, ?HEADER, "<body type='error' xmlns='"++?NS_HTTP_BIND++"'/>"}; {200, ?HEADER, "<body type='error' xmlns='"++?NS_HTTP_BIND_s++"'/>"};
{ok, empty} -> {ok, empty} ->
{200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND_s++"'/>"};
{ok, terminate} -> {ok, terminate} ->
{200, ?HEADER, "<body type='terminate' xmlns='"++?NS_HTTP_BIND++"'/>"}; {200, ?HEADER, "<body type='terminate' xmlns='"++?NS_HTTP_BIND_s++"'/>"};
{ok, ROutPacket} -> {ok, ROutPacket} ->
OutPacket = lists:reverse(ROutPacket), OutPacket = lists:reverse(ROutPacket),
?DEBUG("OutPacket: ~p", [OutPacket]), ?DEBUG("OutPacket: ~p", [OutPacket]),
@ -915,17 +937,26 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold, to=To}=Sess,
[] -> [] ->
[]; [];
[{xmlstreamelement, [{xmlstreamelement,
{xmlelement, "stream:features", #xmlel{name = 'features',
StreamAttribs, StreamEls}} declared_ns = [{undefined, ?NS_XMPP_pfx}],
attrs = StreamAttribs,
children = StreamEls}}
| StreamTail] -> | StreamTail] ->
% {xmlelement, "stream:features",
% StreamAttribs, StreamEls}}
% | StreamTail] ->
TypedTail = TypedTail =
[check_default_xmlns(OEl) || [check_default_xmlns(OEl) ||
{xmlstreamelement, OEl} <- {xmlstreamelement, OEl} <-
StreamTail], StreamTail],
[{xmlelement, "stream:features", [#xmlel{name = 'features',
[{"xmlns:stream", declared_ns = [{?NS_XMPP_s, ?NS_XMPP_pfx}],
?NS_STREAM}] ++ attrs = StreamAttribs,
StreamAttribs, StreamEls}] ++ children = StreamEls}] ++
% [{xmlelement, "stream:features",
% [{"xmlns:stream",
% ?NS_XMPP_s}] ++
% StreamAttribs, StreamEls}] ++
TypedTail; TypedTail;
StreamTail -> StreamTail ->
[check_default_xmlns(OEl) || [check_default_xmlns(OEl) ||
@ -934,8 +965,8 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold, to=To}=Sess,
end, end,
BOSH_attribs = BOSH_attribs =
[{"authid", AuthID}, [{"authid", AuthID},
{"xmlns:xmpp", ?NS_BOSH}, {"xmlns:xmpp", ?NS_BOSH_s},
{"xmlns:stream", ?NS_STREAM}] ++ {"xmlns:stream", ?NS_XMPP_s}] ++
case OutEls of case OutEls of
[] -> [] ->
[]; [];
@ -946,34 +977,76 @@ prepare_response(#http_bind{id=Sid, wait=Wait, hold=Hold, to=To}=Sess,
MaxPause = get_max_pause(To), MaxPause = get_max_pause(To),
{200, ?HEADER, {200, ?HEADER,
xml:element_to_string( xml:element_to_string(
{xmlelement,"body", #xmlel{name = 'body',
[{"xmlns", ns = ?NS_HTTP_BIND_s,
?NS_HTTP_BIND}, attrs = [
{"sid", Sid}, #xmlattr{name = 'sid',
{"wait", integer_to_list(Wait)}, ns = ?NS_HTTP_BIND_s,
{"requests", integer_to_list(Hold+1)}, value = Sid
{"inactivity", },
integer_to_list( #xmlattr{name = 'wait',
trunc(MaxInactivity/1000))}, ns = ?NS_HTTP_BIND_s,
{"maxpause", value = integer_to_list(Wait)
integer_to_list(MaxPause)}, },
{"polling", #xmlattr{name = 'requests',
integer_to_list( ns = ?NS_HTTP_BIND_s,
trunc(?MIN_POLLING/1000000))}, value = integer_to_list(Hold+1)
{"ver", ?BOSH_VERSION}, },
{"from", From}, #xmlattr{name = 'inactivity',
{"secure", "true"} %% we're always being secure ns = ?NS_HTTP_BIND_s,
] ++ BOSH_attribs,OutEls})}; value = integer_to_list(trunc(MaxInactivity/1000))
},
#xmlattr{name = 'maxpause',
ns = ?NS_HTTP_BIND_s,
value = integer_to_list(MaxPause)
},
#xmlattr{name = 'polling',
ns = ?NS_HTTP_BIND_s,
value = integer_to_list(trunc(?MIN_POLLING/1000000))
},
#xmlattr{name = 'ver',
ns = ?NS_HTTP_BIND_s,
value = ?BOSH_VERSION
},
#xmlattr{name = 'from',
ns = ?NS_HTTP_BIND_s,
value = From
},
#xmlattr{name = 'secure',
ns = ?NS_HTTP_BIND_s,
value = "true"
},
BOSH_attribs
],
children = OutEls})};
% {xmlelement,"body",
% [{"xmlns",
% ?NS_HTTP_BIND_s},
% {"sid", Sid},
% {"wait", integer_to_list(Wait)},
% {"requests", integer_to_list(Hold+1)},
% {"inactivity",
% integer_to_list(
% trunc(MaxInactivity/1000))},
% {"maxpause",
% integer_to_list(MaxPause)},
% {"polling",
% integer_to_list(
% trunc(?MIN_POLLING/1000000))},
% {"ver", ?BOSH_VERSION},
% {"from", From},
% {"secure", "true"} %% we're always being secure
% ] ++ BOSH_attribs,OutEls})};
{error, _} -> {error, _} ->
{200, ?HEADER, "<body type='terminate' " {200, ?HEADER, "<body type='terminate' "
"condition='host-unknown' " "condition='host-unknown' "
"xmlns='"++?NS_HTTP_BIND++"'/>"} "xmlns='"++?NS_HTTP_BIND_s++"'/>"}
end end
end; end;
{'EXIT', {shutdown, _}} -> {'EXIT', {shutdown, _}} ->
{200, ?HEADER, "<body type='terminate' condition='system-shutdown' xmlns='"++?NS_HTTP_BIND++"'/>"}; {200, ?HEADER, "<body type='terminate' condition='system-shutdown' xmlns='"++?NS_HTTP_BIND_s++"'/>"};
{'EXIT', _Reason} -> {'EXIT', _Reason} ->
{200, ?HEADER, "<body type='terminate' xmlns='"++?NS_HTTP_BIND++"'/>"} {200, ?HEADER, "<body type='terminate' xmlns='"++?NS_HTTP_BIND_s++"'/>"}
end. end.
http_get(#http_bind{pid = FsmRef, wait = Wait, hold = Hold}, Rid) -> http_get(#http_bind{pid = FsmRef, wait = Wait, hold = Hold}, Rid) ->
@ -983,10 +1056,10 @@ http_get(#http_bind{pid = FsmRef, wait = Wait, hold = Hold}, Rid) ->
send_outpacket(#http_bind{pid = FsmRef}, OutPacket) -> send_outpacket(#http_bind{pid = FsmRef}, OutPacket) ->
case OutPacket of case OutPacket of
[] -> [] ->
{200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND_s++"'/>"};
[{xmlstreamend, _}] -> [{xmlstreamend, _}] ->
gen_fsm:sync_send_all_state_event(FsmRef,{stop,stream_closed}), gen_fsm:sync_send_all_state_event(FsmRef,{stop,stream_closed}),
{200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND++"'/>"}; {200, ?HEADER, "<body xmlns='"++?NS_HTTP_BIND_s++"'/>"};
_ -> _ ->
%% TODO: We parse to add a default namespace to packet, %% TODO: We parse to add a default namespace to packet,
%% The spec says adding the jabber:client namespace if %% The spec says adding the jabber:client namespace if
@ -996,7 +1069,9 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) ->
%% packet in most case. %% packet in most case.
AllElements = AllElements =
lists:all(fun({xmlstreamelement, lists:all(fun({xmlstreamelement,
{xmlelement, "stream:error", _, _}}) -> false; #xmlel{name = 'error',
declared_ns = [{undefined, ?NS_XMPP_pfx}]}}) -> false;
% {xmlelement, "stream:error", _, _}}) -> false;
({xmlstreamelement, _}) -> true; ({xmlstreamelement, _}) -> true;
(_) -> false (_) -> false
end, OutPacket), end, OutPacket),
@ -1005,10 +1080,13 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) ->
TypedEls = [check_default_xmlns(OEl) || TypedEls = [check_default_xmlns(OEl) ||
{xmlstreamelement, OEl} <- OutPacket], {xmlstreamelement, OEl} <- OutPacket],
Body = xml:element_to_string( Body = xml:element_to_string(
{xmlelement,"body", #xmlel{name = 'body',
[{"xmlns", ns = ?NS_HTTP_BIND_s,
?NS_HTTP_BIND}], children = TypedEls}),
TypedEls}), % {xmlelement,"body",
% [{"xmlns",
% ?NS_HTTP_BIND_s}],
% TypedEls}),
?DEBUG(" --- outgoing data --- ~n~s~n --- END --- ~n", ?DEBUG(" --- outgoing data --- ~n~s~n --- END --- ~n",
[Body]), [Body]),
{200, ?HEADER, Body}; {200, ?HEADER, Body};
@ -1018,19 +1096,27 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) ->
OutEls = OutEls =
case SEls of case SEls of
[{xmlstreamelement, [{xmlstreamelement,
{xmlelement, #xmlel{name = 'features',
"stream:features", declared_ns = [{undefined, 'stream'}],
StreamAttribs, StreamEls}} | attrs = StreamAttribs,
children = StreamEls}} |
% {xmlelement,
% "stream:features",
% StreamAttribs, StreamEls}} |
StreamTail] -> StreamTail] ->
TypedTail = TypedTail =
[check_default_xmlns(OEl) || [check_default_xmlns(OEl) ||
{xmlstreamelement, OEl} <- {xmlstreamelement, OEl} <-
StreamTail], StreamTail],
[{xmlelement, [#xmlel{name = 'features',
"stream:features", declared_ns = [{?NS_XMPP_s, ?NS_XMPP_pfx}],
[{"xmlns:stream", attrs = StreamAttribs,
?NS_STREAM}] ++ children = StreamEls}] ++
StreamAttribs, StreamEls}] ++ % [{xmlelement,
% "stream:features",
% [{"xmlns:stream",
% ?NS_XMPP_s}] ++
% StreamAttribs, StreamEls}] ++
TypedTail; TypedTail;
StreamTail -> StreamTail ->
[check_default_xmlns(OEl) || [check_default_xmlns(OEl) ||
@ -1039,16 +1125,21 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) ->
end, end,
{200, ?HEADER, {200, ?HEADER,
xml:element_to_string( xml:element_to_string(
{xmlelement,"body", #xmlel{name = 'body',
[{"xmlns", ns = ?NS_HTTP_BIND_s,
?NS_HTTP_BIND}], children = OutEls})};
OutEls})}; % {xmlelement,"body",
% [{"xmlns",
% ?NS_HTTP_BIND_s}],
% OutEls})};
_ -> _ ->
SErrCond = SErrCond =
lists:filter( lists:filter(
fun({xmlstreamelement, fun({xmlstreamelement,
{xmlelement, "stream:error", #xmlel{name = 'error',
_, _}}) -> declared_ns = [{undefined, ?NS_XMPP_pfx}]}}) ->
% {xmlelement, "stream:error",
% _, _}}) ->
true; true;
(_) -> false (_) -> false
end, OutPacket), end, OutPacket),
@ -1057,7 +1148,8 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) ->
[] -> [] ->
null; null;
[{xmlstreamelement, [{xmlstreamelement,
{xmlelement, _, _, _Cond} = #xmlel{children = _Cond} =
% {xmlelement, _, _, _Cond} =
StreamErrorTag} | _] -> StreamErrorTag} | _] ->
[StreamErrorTag] [StreamErrorTag]
end, end,
@ -1068,13 +1160,13 @@ send_outpacket(#http_bind{pid = FsmRef}, OutPacket) ->
{200, ?HEADER, {200, ?HEADER,
"<body type='terminate' " "<body type='terminate' "
"condition='internal-server-error' " "condition='internal-server-error' "
"xmlns='"++?NS_HTTP_BIND++"'/>"}; "xmlns='"++?NS_HTTP_BIND_s++"'/>"};
_ -> _ ->
{200, ?HEADER, {200, ?HEADER,
"<body type='terminate' " "<body type='terminate' "
"condition='remote-stream-error' " "condition='remote-stream-error' "
"xmlns='"++?NS_HTTP_BIND++"' " ++ "xmlns='"++?NS_HTTP_BIND_s++"' " ++
"xmlns:stream='"++?NS_STREAM++"'>" ++ "xmlns:stream='"++?NS_XMPP_s++"'>" ++
elements_to_string(StreamErrCond) ++ elements_to_string(StreamErrCond) ++
"</body>"} "</body>"}
end end
@ -1087,13 +1179,19 @@ parse_request(Data, PayloadSize, MaxStanzaSize) ->
%% MR: I do not think it works if put put several elements in the %% MR: I do not think it works if put put several elements in the
%% same body: %% same body:
case xml_stream:parse_element(Data) of case xml_stream:parse_element(Data) of
{xmlelement, "body", Attrs, Els} -> #xmlel{name = 'body',
Xmlns = xml:get_attr_s("xmlns",Attrs), ns = Xmlns,
attrs = Attrs,
children = Els} = Xml->
% {xmlelement, "body", Attrs, Els} ->
% Xmlns = xml:get_attr_s("xmlns",Attrs),
if if
Xmlns /= ?NS_HTTP_BIND -> Xmlns /= ?NS_HTTP_BIND_s ->
{error, bad_request}; {error, bad_request};
true -> true ->
case catch list_to_integer(xml:get_attr_s("rid", Attrs)) of %case catch list_to_integer(xml:get_attr_s("rid", Attrs)) of
case catch list_to_integer(exmpp_xml:get_attribute_as_list(Xml, "rid", "")) of
{'EXIT', _} -> {'EXIT', _} ->
{error, bad_request}; {error, bad_request};
Rid -> Rid ->
@ -1102,12 +1200,14 @@ parse_request(Data, PayloadSize, MaxStanzaSize) ->
lists:filter( lists:filter(
fun(I) -> fun(I) ->
case I of case I of
{xmlelement, _, _, _} -> #xmlel{} ->
%{xmlelement, _, _, _} ->
true; true;
_ -> _ ->
false false
end end
end, Els), end, Els),
% Suggestion : Sid = exmpp_xml:get_attribute_as_list(Xml, "sid", ""),
Sid = xml:get_attr_s("sid",Attrs), Sid = xml:get_attr_s("sid",Attrs),
if if
PayloadSize =< MaxStanzaSize -> PayloadSize =< MaxStanzaSize ->
@ -1117,7 +1217,8 @@ parse_request(Data, PayloadSize, MaxStanzaSize) ->
end end
end end
end; end;
{xmlelement, _Name, _Attrs, _Els} -> #xmlel{} ->
% {xmlelement, _Name, _Attrs, _Els} ->
{error, bad_request}; {error, bad_request};
{error, _Reason} -> {error, _Reason} ->
{error, bad_request} {error, bad_request}
@ -1178,9 +1279,12 @@ tnow() ->
{TMegSec, TSec, TMSec} = now(), {TMegSec, TSec, TMSec} = now(),
(TMegSec * 1000000 + TSec) * 1000000 + TMSec. (TMegSec * 1000000 + TSec) * 1000000 + TMSec.
check_default_xmlns({xmlelement, Name, Attrs, Els} = El) -> check_default_xmlns(#xmlel{name = Name, ns = Xmlns, attrs = Attrs, children = Els} = El) ->
case xml:get_tag_attr_s("xmlns", El) of %check_default_xmlns({xmlelement, Name, Attrs, Els} = El) ->
"" -> {xmlelement, Name, [{"xmlns", ?NS_CLIENT} | Attrs], Els}; case Xmlns of
% case xml:get_tag_attr_s("xmlns", El) of
"" -> #xmlel{name = Name, ns = ?NS_JABBER_CLIENT_s, attrs = Attrs, children = Els};
% "" -> {xmlelement, Name, [{"xmlns", ?NS_JABBER_CLIENT_s} | Attrs], Els};
_ -> El _ -> El
end. end.