-spec dec_utc(_) -> erlang:timestamp().
dec_utc(Val) ->
- {_, _, _} = jlib:datetime_string_to_timestamp(Val).
+ xmpp_util:decode_timestamp(Val).
enc_utc(Val) ->
- jlib:now_to_utc_string(Val).
+ xmpp_util:encode_timestamp(Val).
-spec dec_jid(_) -> jid:jid().
dec_jid(Val) ->
TTL = proplists:get_value(<<"ttl">>, Q, <<"">>),
ExpiresIn = case TTL of
<<>> -> undefined;
- _ -> jlib:binary_to_integer(TTL)
+ _ -> binary_to_integer(TTL)
end,
case oauth2:authorize_password({Username, Server},
ClientId,
TTL = proplists:get_value(<<"ttl">>, Q, <<"">>),
ExpiresIn = case TTL of
<<>> -> undefined;
- _ -> jlib:binary_to_integer(TTL)
+ _ -> binary_to_integer(TTL)
end,
case oauth2:authorize_password({Username, Server},
Scope,
binary_to_integer/1,
integer_to_binary/1]}).
+-export([tolower/1, term_to_base64/1, base64_to_term/1,
+ decode_base64/1, encode_base64/1, ip_to_list/1,
+ atom_to_binary/1, binary_to_atom/1, tuple_to_binary/1,
+ l2i/1, i2l/1, i2l/2, queue_drop_while/2,
+ expr_to_term/1, term_to_expr/1]).
+
+%% The following functions are used by gen_iq_handler.erl for providing backward
+%% compatibility and must not be used in other parts of the code
+%% Use xmpp:decode() and xmpp:encode() instead
+-export([iq_query_info/1, iq_to_xml/1]).
+
+%% The following functions are deprecated and will be removed soon
+%% Use functions from xmpp.erl and xmpp_util.erl instead
-export([make_result_iq_reply/1, make_error_reply/3,
make_error_reply/2, make_error_element/2,
make_correct_from_to_attrs/3, replace_from_to_attrs/3,
replace_from_to/3, replace_from_attrs/2, replace_from/2,
- remove_attr/2, tolower/1,
- get_iq_namespace/1, iq_query_info/1,
+ remove_attr/2, get_iq_namespace/1,
iq_query_or_response_info/1, is_iq_request_type/1,
- iq_to_xml/1, parse_xdata_submit/1,
- unwrap_carbon/1, is_standalone_chat_state/1,
+ parse_xdata_submit/1, unwrap_carbon/1, is_standalone_chat_state/1,
add_delay_info/3, add_delay_info/4,
timestamp_to_legacy/1, timestamp_to_iso_basic/1, timestamp_to_iso/2,
now_to_utc_string/1, now_to_local_string/1,
datetime_string_to_timestamp/1,
- term_to_base64/1, base64_to_term/1,
- decode_base64/1, encode_base64/1, ip_to_list/1,
rsm_encode/1, rsm_encode/2, rsm_decode/1,
binary_to_integer/1, binary_to_integer/2,
- integer_to_binary/1, integer_to_binary/2,
- atom_to_binary/1, binary_to_atom/1, tuple_to_binary/1,
- l2i/1, i2l/1, i2l/2, queue_drop_while/2,
- expr_to_term/1, term_to_expr/1]).
+ integer_to_binary/1, integer_to_binary/2]).
%% The following functions are deprecated and will be removed soon
%% Use corresponding functions from jid.erl instead
{jid_tolower, 1},
{jid_remove_resource, 1},
{jid_replace_resource, 2},
+ {add_delay_info, 3},
+ {add_delay_info, 4},
+ {make_result_iq_reply, 1},
+ {make_error_reply, 3},
+ {make_error_reply, 2},
+ {make_error_element, 2},
+ {make_correct_from_to_attrs, 3},
+ {replace_from_to_attrs, 3},
+ {replace_from_to, 3},
+ {replace_from_attrs, 2},
+ {replace_from, 2},
+ {remove_attr, 2},
+ {get_iq_namespace, 1},
+ {iq_query_or_response_info, 1},
+ {is_iq_request_type, 1},
+ {parse_xdata_submit, 1},
+ {unwrap_carbon, 1},
+ {is_standalone_chat_state, 1},
+ {timestamp_to_legacy, 1},
+ {timestamp_to_iso_basic, 1},
+ {timestamp_to_iso, 2},
+ {now_to_utc_string, 1},
+ {now_to_local_string, 1},
+ {datetime_string_to_timestamp, 1},
+ {rsm_encode, 1},
+ {rsm_encode, 2},
+ {rsm_decode, 1},
+ {binary_to_integer, 1},
+ {binary_to_integer, 2},
{integer_to_binary, 1},
- {binary_to_integer, 1}]).
+ {integer_to_binary, 2}]).
-include("ejabberd.hrl").
-include("jlib.hrl").
set_password_auth(User, Server, NewPass).
build_random_password(Reason) ->
- Date = jlib:timestamp_to_legacy(calendar:universal_time()),
+ {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:universal_time(),
+ Date = str:format("~4..0B~2..0B~2..0BT~2..0B:~2..0B:~2..0B",
+ [Year, Month, Day, Hour, Minute, Second]),
RandomString = randoms:get_string(),
<<"BANNED_ACCOUNT--", Date/binary, "--", RandomString/binary, "--", Reason/binary>>.
try
lists:foldl(
fun(#xdata_field{var = <<"start">>, values = [Data|_]}, Q) ->
- case jlib:datetime_string_to_timestamp(Data) of
- undefined -> throw({error, <<"start">>});
+ try xmpp_util:decode_timestamp(Data) of
{_, _, _} = TS -> Q#mam_query{start = TS}
+ catch _:{bad_timestamp, _} -> throw({error, <<"start">>})
end;
(#xdata_field{var = <<"end">>, values = [Data|_]}, Q) ->
- case jlib:datetime_string_to_timestamp(Data) of
- undefined -> throw({error, <<"end">>});
- {_, _, _} = TS -> Q#mam_query{'end' = TS}
+ try xmpp_util:decode_timestamp(Data) of
+ {_, _, _} = TS -> Q#mam_query{start = TS}
+ catch _:{bad_timestamp, _} -> throw({error, <<"end">>})
end;
(#xdata_field{var = <<"with">>, values = [Data|_]}, Q) ->
case jid:from_string(Data) of
false ->
Last_message1 = queue:last(History),
{_, _, _, Ts_last, _} = Last_message1,
- jlib:timestamp_to_legacy(Ts_last)
+ xmpp_util:encode_timestamp(Ts_last)
end,
{<<Name/binary, "@", Host/binary>>,
BareJID = jid:remove_resource(JID),
Pid ! dont_ask_offline,
{result, lists:map(
- fun({Seq, From, _To, _El}) ->
+ fun({Seq, From, _To, _TS, _El}) ->
Node = integer_to_binary(Seq),
#disco_item{jid = BareJID,
node = Node,
Pid when is_pid(Pid) ->
Pid ! dont_ask_offline,
lists:foreach(
- fun({Node, From, To, El}) ->
+ fun({Node, El}) ->
NewEl = set_offline_tag(El, Node),
- Pid ! {route, From, To, NewEl}
- end, read_message_headers(U, S))
+ Pid ! {route, xmpp:get_from(El), xmpp:get_to(El), NewEl}
+ end, read_messages(U, S))
end.
-spec fetch_msg_by_node(jid(), binary()) -> error | {ok, #offline_msg{}}.
NewPacket ->
TimeStamp = p1_time_compat:timestamp(),
Expire = find_x_expire(TimeStamp, NewPacket),
- El = xmpp:encode(NewPacket),
gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME) !
#offline_msg{us = {LUser, LServer},
- timestamp = TimeStamp, expire = Expire,
- from = From, to = To, packet = El},
+ timestamp = TimeStamp,
+ expire = Expire,
+ from = From,
+ to = To,
+ packet = NewPacket},
stop
end;
_ -> ok
Mod = gen_mod:db_mod(LServer, ?MODULE),
case Mod:pop_messages(LUser, LServer) of
{ok, Rs} ->
- lists:foreach(fun (R) ->
- ejabberd_sm ! offline_msg_to_route(LServer, R)
- end,
- lists:keysort(#offline_msg.timestamp, Rs));
+ lists:foreach(
+ fun(R) ->
+ case offline_msg_to_route(LServer, R) of
+ error -> ok;
+ RouteMsg -> ejabberd_sm ! RouteMsg
+ end
+ end, lists:keysort(#offline_msg.timestamp, Rs));
_ -> ok
end.
{ok, Rs} ->
TS = p1_time_compat:timestamp(),
Ls ++
- lists:map(fun (R) ->
- offline_msg_to_route(LServer, R)
- end,
- lists:filter(
- fun(#offline_msg{packet = Pkt} = R) ->
- Expire = case R#offline_msg.expire of
- undefined ->
- find_x_expire(TS, Pkt);
- Exp ->
- Exp
- end,
- case Expire of
- never -> true;
- TimeStamp -> TS < TimeStamp
- end
- end, Rs));
+ lists:flatmap(
+ fun(R) ->
+ case offline_msg_to_route(LServer, R) of
+ error -> [];
+ RouteMsg -> [RouteMsg]
+ end
+ end,
+ lists:filter(
+ fun(#offline_msg{packet = Pkt} = R) ->
+ Expire = case R#offline_msg.expire of
+ undefined ->
+ find_x_expire(TS, Pkt);
+ Exp ->
+ Exp
+ end,
+ case Expire of
+ never -> true;
+ TimeStamp -> TS < TimeStamp
+ end
+ end, Rs));
_ ->
Ls
end.
webadmin_page(Acc, _, _) -> Acc.
get_offline_els(LUser, LServer) ->
- Hdrs = read_message_headers(LUser, LServer),
- lists:map(
- fun({_Seq, From, To, Packet}) ->
- xmpp:set_from_to(Packet, From, To)
- end, Hdrs).
+ [Packet || {_Seq, Packet} <- read_messages(LUser, LServer)].
+-spec offline_msg_to_route(binary(), #offline_msg{}) ->
+ {route, jid(), jid(), message()} | error.
offline_msg_to_route(LServer, #offline_msg{} = R) ->
- Pkt = xmpp:decode(R#offline_msg.packet, ?NS_CLIENT, [ignore_els]),
- Pkt1 = case R#offline_msg.timestamp of
- undefined ->
- Pkt;
- TS ->
- xmpp_util:add_delay_info(Pkt, jid:make(LServer), TS,
- <<"Offline Storage">>)
- end,
- {route, R#offline_msg.from, R#offline_msg.to, Pkt1}.
-
-read_message_headers(LUser, LServer) ->
+ try xmpp:decode(R#offline_msg.packet, ?NS_CLIENT, [ignore_els]) of
+ Pkt ->
+ NewPkt = add_delay_info(Pkt, LServer, R#offline_msg.timestamp),
+ {route, R#offline_msg.from, R#offline_msg.to, NewPkt}
+ catch _:{xmpp_codec, Why} ->
+ ?ERROR_MSG("failed to decode packet ~p of user ~s: ~s",
+ [R#offline_msg.packet, jid:to_string(R#offline_msg.to),
+ xmpp:format_error(Why)]),
+ error
+ end.
+
+-spec read_messages(binary(), binary()) -> [{binary(), message()}].
+read_messages(LUser, LServer) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
- lists:map(
- fun({Seq, From, To, El}) ->
+ lists:flatmap(
+ fun({Seq, From, To, TS, El}) ->
Node = integer_to_binary(Seq),
- Packet = xmpp:decode(El, ?NS_CLIENT, [ignore_els]),
- {Node, From, To, Packet}
+ try xmpp:decode(El, ?NS_CLIENT, [ignore_els]) of
+ Pkt ->
+ Node = integer_to_binary(Seq),
+ Pkt1 = add_delay_info(Pkt, LServer, TS),
+ Pkt2 = xmpp:set_from_to(Pkt1, From, To),
+ [{Node, Pkt2}]
+ catch _:{xmpp_codec, Why} ->
+ ?ERROR_MSG("failed to decode packet ~p "
+ "of user ~s: ~s",
+ [El, jid:to_string(To),
+ xmpp:format_error(Why)]),
+ []
+ end
end, Mod:read_message_headers(LUser, LServer)).
format_user_queue(Hdrs) ->
lists:map(
- fun({Seq, From, To, El}) ->
+ fun({Seq, From, To, TS, El}) ->
ID = integer_to_binary(Seq),
FPacket = ejabberd_web_admin:pretty_print_xml(El),
SFrom = jid:to_string(From),
STo = jid:to_string(To),
- Stamp = fxml:get_path_s(El, [{elem, <<"delay">>},
- {attr, <<"stamp">>}]),
- Time = case jlib:datetime_string_to_timestamp(Stamp) of
+ Time = case TS of
+ undefined ->
+ Stamp = fxml:get_path_s(El, [{elem, <<"delay">>},
+ {attr, <<"stamp">>}]),
+ try xmpp_util:decode_timestamp(Stamp) of
+ {_, _, _} = Now -> format_time(Now)
+ catch _:_ ->
+ <<"">>
+ end;
{_, _, _} = Now ->
- {{Year, Month, Day}, {Hour, Minute, Second}} =
- calendar:now_to_local_time(Now),
- iolist_to_binary(
- io_lib:format(
- "~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w",
- [Year, Month, Day, Hour, Minute,
- Second]));
- _ ->
- <<"">>
+ format_time(Now)
end,
?XE(<<"tr">>,
[?XAE(<<"td">>, [{<<"class">>, <<"valign">>}],
[?XC(<<"pre">>, FPacket)])])
end, Hdrs).
+format_time(Now) ->
+ {{Year, Month, Day}, {Hour, Minute, Second}} = calendar:now_to_local_time(Now),
+ str:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w",
+ [Year, Month, Day, Hour, Minute, Second]).
+
user_queue(User, Server, Query, Lang) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
Mod = gen_mod:db_mod(LServer, ?MODULE),
Mod:count_messages(LUser, LServer).
+-spec add_delay_info(message(), binary(),
+ undefined | erlang:timestamp()) -> message().
+add_delay_info(Packet, _LServer, undefined) ->
+ Packet;
+add_delay_info(Packet, LServer, {_, _, _} = TS) ->
+ xmpp_util:add_delay_info(Packet, jid:make(LServer), TS,
+ <<"Offline storage">>).
+
export(LServer) ->
Mod = gen_mod:db_mod(LServer, ?MODULE),
Mod:export(LServer).
mnesia:write_lock_table(offline_msg);
true -> ok
end,
- lists:foreach(fun (M) -> mnesia:write(M) end, Msgs)
+ lists:foreach(
+ fun(#offline_msg{packet = Pkt} = M) ->
+ El = xmpp:encode(Pkt),
+ mnesia:write(M#offline_msg{packet = El})
+ end, Msgs)
end
end,
mnesia:transaction(F).
fun(#offline_msg{from = From, to = To, packet = Pkt,
timestamp = TS}) ->
Seq = now_to_integer(TS),
- NewPkt = jlib:add_delay_info(Pkt, LServer, TS,
- <<"Offline Storage">>),
- {Seq, From, To, NewPkt}
+ {Seq, From, To, TS, Pkt}
end, Msgs),
lists:keysort(1, Hdrs).
try
lists:foreach(
fun(#offline_msg{us = US,
+ packet = Pkt,
timestamp = TS} = M) ->
+ El = xmpp:encode(Pkt),
ok = ejabberd_riak:put(
- M, offline_msg_schema(),
+ M#offline_msg{packet = El},
+ offline_msg_schema(),
[{i, TS}, {'2i', [{<<"us">>, US}]}])
end, Msgs),
{atomic, ok}
fun(#offline_msg{from = From, to = To, packet = Pkt,
timestamp = TS}) ->
Seq = now_to_integer(TS),
- NewPkt = jlib:add_delay_info(
- Pkt, LServer, TS, <<"Offline Storage">>),
- {Seq, From, To, NewPkt}
+ {Seq, From, To, Pkt}
end, Rs),
lists:keysort(1, Hdrs);
_Err ->
LUser = (M#offline_msg.to)#jid.luser,
From = M#offline_msg.from,
To = M#offline_msg.to,
- Packet =
- jlib:replace_from_to(From, To,
- M#offline_msg.packet),
- NewPacket =
- jlib:add_delay_info(Packet, Host,
- M#offline_msg.timestamp,
- <<"Offline Storage">>),
- XML = fxml:element_to_binary(NewPacket),
+ Packet = xmpp:set_from_to(
+ M#offline_msg.packet, From, To),
+ NewPacket = xmpp_util:add_delay_info(
+ Packet, jid:make(Host),
+ M#offline_msg.timestamp,
+ <<"Offline Storage">>),
+ XML = fxml:element_to_binary(
+ xmpp:encode(NewPacket)),
sql_queries:add_spool_sql(LUser, XML)
end,
Msgs),
[{offline_msg,
fun(Host, #offline_msg{us = {LUser, LServer},
timestamp = TimeStamp, from = From, to = To,
- packet = Packet})
+ packet = El})
when LServer == Host ->
- Packet1 = jlib:replace_from_to(From, To, Packet),
- Packet2 = jlib:add_delay_info(Packet1, LServer, TimeStamp,
- <<"Offline Storage">>),
- XML = fxml:element_to_binary(Packet2),
- [?SQL("delete from spool where username=%(LUser)s;"),
- ?SQL("insert into spool(username, xml) values ("
- "%(LUser)s, %(XML)s);")];
+ try xmpp:decode(El, ?NS_CLIENT, [ignore_els]) of
+ Packet ->
+ Packet1 = xmpp:set_from_to(Packet, From, To),
+ Packet2 = xmpp_util:add_delay_info(
+ Packet1, jid:make(LServer),
+ TimeStamp, <<"Offline Storage">>),
+ XML = fxml:element_to_binary(xmpp:encode(Packet2)),
+ [?SQL("delete from spool where username=%(LUser)s;"),
+ ?SQL("insert into spool(username, xml) values ("
+ "%(LUser)s, %(XML)s);")]
+ catch _:{xmpp_codec, Why} ->
+ ?ERROR_MSG("failed to decode packet ~p of user ~s@~s: ~s",
+ [El, LUser, LServer, xmpp:format_error(Why)]),
+ []
+ end;
(_Host, _R) ->
[]
end}].
[{<<"select username, xml from spool;">>,
fun([LUser, XML]) ->
El = #xmlel{} = fxml_stream:parse_element(XML),
- From = #jid{} = jid:from_string(
- fxml:get_attr_s(<<"from">>, El#xmlel.attrs)),
- To = #jid{} = jid:from_string(
- fxml:get_attr_s(<<"to">>, El#xmlel.attrs)),
- Stamp = fxml:get_path_s(El, [{elem, <<"delay">>},
- {attr, <<"stamp">>}]),
- TS = case jlib:datetime_string_to_timestamp(Stamp) of
- {_, _, _} = Now ->
- Now;
- undefined ->
- p1_time_compat:timestamp()
- end,
- Expire = mod_offline:find_x_expire(TS, El#xmlel.children),
- #offline_msg{us = {LUser, LServer},
- from = From, to = To,
+ #message{} = Pkt = xmpp:decode(El, ?NS_CLIENT, [ignore_els]),
+ From = Pkt#message.from,
+ To = case Pkt#message.to of
+ undefined -> jid:make(LUser, LServer);
+ JID -> JID
+ end,
+ TS = case xmpp:get_subtag(Pkt, #delay{}) of
+ #delay{stamp = Stamp} -> Stamp;
+ false -> p1_time_compat:timestamp()
+ end,
+ Expire = mod_offline:find_x_expire(TS, Pkt),
+ #offline_msg{us = {LUser, LServer},
+ from = From, to = To,
packet = El,
- timestamp = TS, expire = Expire}
+ timestamp = TS, expire = Expire}
end}].
import(_, _) ->
match_presence_out = MatchPresOut}.
el_to_offline_msg(LUser, LServer, #xmlel{attrs = Attrs} = El) ->
- case jlib:datetime_string_to_timestamp(
- fxml:get_attr_s(<<"stamp">>, Attrs)) of
+ try xmpp_util:decode_timestamp(
+ fxml:get_attr_s(<<"stamp">>, Attrs)) of
{_, _, _} = TS ->
Attrs1 = lists:filter(
fun(<<"stamp">>) -> false;
packet = Packet}];
_ ->
[]
- end;
- _ ->
+ end
+ catch _:{bad_timestamp, _} ->
[]
end.
boolean_to_sql(true) -> <<"1">>;
boolean_to_sql(false) -> <<"0">>.
-timestamp_to_sql(T) -> jlib:now_to_utc_string(T).
+timestamp_to_sql(T) -> xmpp_util:encode_timestamp(T).
sql_to_integer(N) -> binary_to_integer(N).
sql_to_boolean(B) -> B == <<"1">>.
-sql_to_timestamp(T) -> jlib:datetime_string_to_timestamp(T).
+sql_to_timestamp(T) -> xmpp_util:decode_timestamp(T).
{error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}
end;
val_xfield(expire = Opt, [Val]) ->
- case jlib:datetime_string_to_timestamp(Val) of
- undefined ->
+ try xmpp_util:decode_timestamp(Val)
+ catch _:{bad_timestamp, _} ->
Txt = <<"Value of '~s' should be datetime string">>,
ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])),
- {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)};
- Timestamp ->
- Timestamp
+ {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}
end;
val_xfield(include_body = Opt, [Val]) -> xopt_to_bool(Opt, Val);
val_xfield(show_values, Vals) -> Vals;
{error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}
end;
val_xfield(expire = Opt, [Val]) ->
- case jlib:datetime_string_to_timestamp(Val) of
- undefined ->
+ try xmpp_util:decode_timestamp(Val)
+ catch _:{bad_timestamp, _} ->
Txt = <<"Value of '~s' should be datetime string">>,
ErrTxt = iolist_to_binary(io_lib:format(Txt, [Opt])),
- {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)};
- Timestamp ->
- Timestamp
+ {error, xmpp:err_not_acceptable(ErrTxt, ?MYLANG)}
end;
val_xfield(include_body = Opt, [Val]) -> xopt_to_bool(Opt, Val);
val_xfield(show_values, Vals) -> Vals;
get_string() ->
R = crypto:rand_uniform(0, ?THRESHOLD),
- jlib:integer_to_binary(R).
+ integer_to_binary(R).
uniform() ->
crypto:rand_uniform(0, ?THRESHOLD)/?THRESHOLD.
format_error/1, is_stanza/1, set_subtag/2, get_subtag/2,
remove_subtag/2, has_subtag/2, decode_els/1, decode_els/3,
pp/1, get_name/1, get_text/1, mk_text/1, mk_text/2,
- is_known_tag/1, is_known_tag/2]).
+ is_known_tag/1, is_known_tag/2, append_subtags/2]).
%% XMPP errors
-export([err_bad_request/0, err_bad_request/2,
has_subtag([], _, _) ->
false.
+-spec append_subtags(stanza(), [xmpp_element() | xmlel()]) -> stanza().
+append_subtags(Stanza, Tags) ->
+ Els = get_els(Stanza),
+ set_els(Stanza, Els ++ Tags).
+
-spec get_text([text()]) -> binary().
get_text([]) -> <<"">>;
get_text([#text{data = Data}|_]) -> Data.
J -> J
end.
-enc_utc(Val) -> jlib:now_to_utc_string(Val).
+enc_utc(Val) -> xmpp_util:encode_timestamp(Val).
-dec_utc(Val) ->
- {_, _, _} = jlib:datetime_string_to_timestamp(Val).
+dec_utc(Val) -> xmpp_util:decode_timestamp(Val).
enc_tzo({H, M}) ->
Sign = if H >= 0 -> <<>>;
erlang:timestamp(), binary()) -> stanza().
add_delay_info(Stz, From, Time, Desc) ->
+ NewDelay = #delay{stamp = Time, from = From, desc = Desc},
case xmpp:get_subtag(Stz, #delay{}) of
- #delay{from = OldFrom, desc = OldDesc} = Delay ->
+ #delay{from = OldFrom} ->
case jid:tolower(From) == jid:tolower(OldFrom) of
- true when Desc == <<"">> ->
- Stz;
- true when OldDesc == <<"">> ->
- xmpp:set_subtag(Stz, Delay#delay{desc = Desc});
- true ->
- case binary:match(OldDesc, Desc) of
- nomatch ->
- NewDesc = <<OldDesc/binary, ", ", Desc/binary>>,
- xmpp:set_subtag(Stz, Delay#delay{desc = NewDesc});
- _ ->
- Stz
- end;
false ->
- NewDelay = #delay{stamp = Time, from = From, desc = Desc},
- xmpp:set_subtag(Stz, NewDelay)
+ xmpp:set_subtag(Stz, NewDelay);
+ true ->
+ xmpp:append_subtags(Stz, [NewDelay])
end;
false ->
- Delay = #delay{stamp = Time, from = From, desc = Desc},
- xmpp:set_subtag(Stz, Delay)
+ xmpp:append_subtags(Stz, [NewDelay])
end.
-spec unwrap_carbon(stanza()) -> xmpp_element().
H:2/binary, $:, Mi:2/binary, $:, S:2/binary, $Z>>).
try_decode_fraction(<<$., T/binary>>) ->
- {match, [V]} = re:run(T, <<"^[0-9]+">>, [{capture, [0], binary}]),
- Size = size(V),
- <<V:Size/binary, TZD/binary>> = T,
- {to_integer(binary:part(V, 0, min(6, Size)), 0, 999999),
+ {match, [V]} = re:run(T, <<"^[0-9]+">>, [{capture, [0], list}]),
+ Size = length(V),
+ <<_:Size/binary, TZD/binary>> = T,
+ {list_to_integer(string:left(V, 6, $0)),
try_decode_tzd(TZD)};
try_decode_fraction(TZD) ->
{0, try_decode_tzd(TZD)}.