mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-08 16:52:59 +01:00
Add tests for XEP-0013
This commit is contained in:
parent
02a519a11e
commit
d6323a7b5e
@ -110,7 +110,7 @@ edoc:
|
||||
|
||||
spec:
|
||||
$(ERL) -noinput +B -pa ebin -pa deps/*/ebin -eval \
|
||||
'case xml_gen:compile("tools/xmpp_codec.spec") of ok -> halt(0); _ -> halt(1) end.'
|
||||
'case fxml_gen:compile("tools/xmpp_codec.spec") of ok -> halt(0); _ -> halt(1) end.'
|
||||
|
||||
JOIN_PATHS=$(if $(wordlist 2,1000,$(1)),$(firstword $(1))/$(call JOIN_PATHS,$(wordlist 2,1000,$(1))),$(1))
|
||||
|
||||
|
@ -214,6 +214,8 @@ db_tests(riak) ->
|
||||
{test_roster_subscribe, [parallel],
|
||||
[roster_subscribe_master,
|
||||
roster_subscribe_slave]},
|
||||
{test_flex_offline, [sequence],
|
||||
[flex_offline_master, flex_offline_slave]},
|
||||
{test_offline, [sequence],
|
||||
[offline_master, offline_slave]},
|
||||
{test_muc, [parallel],
|
||||
@ -245,6 +247,8 @@ db_tests(mnesia) ->
|
||||
{test_roster_subscribe, [parallel],
|
||||
[roster_subscribe_master,
|
||||
roster_subscribe_slave]},
|
||||
{test_flex_offline, [sequence],
|
||||
[flex_offline_master, flex_offline_slave]},
|
||||
{test_offline, [sequence],
|
||||
[offline_master, offline_slave]},
|
||||
{test_old_mam, [parallel],
|
||||
@ -285,6 +289,8 @@ db_tests(_) ->
|
||||
{test_roster_subscribe, [parallel],
|
||||
[roster_subscribe_master,
|
||||
roster_subscribe_slave]},
|
||||
{test_flex_offline, [sequence],
|
||||
[flex_offline_master, flex_offline_slave]},
|
||||
{test_offline, [sequence],
|
||||
[offline_master, offline_slave]},
|
||||
{test_old_mam, [parallel],
|
||||
@ -1433,6 +1439,131 @@ announce_slave(Config) ->
|
||||
send(Config, #message{to = MotdDelJID}),
|
||||
disconnect(Config).
|
||||
|
||||
flex_offline_master(Config) ->
|
||||
Peer = ?config(slave, Config),
|
||||
LPeer = jlib:jid_remove_resource(Peer),
|
||||
lists:foreach(
|
||||
fun(I) ->
|
||||
Body = jlib:integer_to_binary(I),
|
||||
send(Config, #message{to = LPeer,
|
||||
body = [#text{data = Body}],
|
||||
subject = [#text{data = <<"subject">>}]})
|
||||
end, lists:seq(1, 5)),
|
||||
disconnect(Config).
|
||||
|
||||
flex_offline_slave(Config) ->
|
||||
MyJID = my_jid(Config),
|
||||
MyBareJID = jid:remove_resource(MyJID),
|
||||
Peer = ?config(master, Config),
|
||||
Peer_s = jid:to_string(Peer),
|
||||
true = is_feature_advertised(Config, ?NS_FLEX_OFFLINE),
|
||||
%% Request disco#info
|
||||
#iq{type = result,
|
||||
sub_els = [#disco_info{
|
||||
node = ?NS_FLEX_OFFLINE,
|
||||
identities = Ids,
|
||||
features = Fts,
|
||||
xdata = [X]}]} =
|
||||
send_recv(Config, #iq{type = get,
|
||||
sub_els = [#disco_info{
|
||||
node = ?NS_FLEX_OFFLINE}]}),
|
||||
%% Check if we have correct identities
|
||||
true = lists:any(
|
||||
fun(#identity{category = <<"automation">>,
|
||||
type = <<"message-list">>}) -> true;
|
||||
(_) -> false
|
||||
end, Ids),
|
||||
%% Check if we have needed feature
|
||||
true = lists:member(?NS_FLEX_OFFLINE, Fts),
|
||||
%% Check xdata, the 'number_of_messages' should be 5
|
||||
#xdata{type = result,
|
||||
fields = [#xdata_field{type = hidden,
|
||||
var = <<"FORM_TYPE">>},
|
||||
#xdata_field{var = <<"number_of_messages">>,
|
||||
values = [<<"5">>]}]} = X,
|
||||
%% Fetch headers,
|
||||
#iq{type = result,
|
||||
sub_els = [#disco_items{
|
||||
node = ?NS_FLEX_OFFLINE,
|
||||
items = DiscoItems}]} =
|
||||
send_recv(Config, #iq{type = get,
|
||||
sub_els = [#disco_items{
|
||||
node = ?NS_FLEX_OFFLINE}]}),
|
||||
%% Check if headers are correct
|
||||
Nodes = lists:sort(
|
||||
lists:map(
|
||||
fun(#disco_item{jid = J, name = P, node = N})
|
||||
when (J == MyBareJID) and (P == Peer_s) ->
|
||||
N
|
||||
end, DiscoItems)),
|
||||
%% Check full fetch
|
||||
I0 = send(Config, #iq{type = get, sub_els = [#offline{fetch = true}]}),
|
||||
lists:foreach(
|
||||
fun({I, N}) ->
|
||||
Text = jlib:integer_to_binary(I),
|
||||
?recv1(#message{body = Body, sub_els = SubEls}),
|
||||
[#text{data = Text}] = Body,
|
||||
#offline{items = [#offline_item{node = N}]} =
|
||||
lists:keyfind(offline, 1, SubEls),
|
||||
#delay{} = lists:keyfind(delay, 1, SubEls)
|
||||
end, lists:zip(lists:seq(1, 5), Nodes)),
|
||||
?recv1(#iq{type = result, id = I0, sub_els = []}),
|
||||
%% Fetch 2nd and 4th message
|
||||
I1 = send(Config,
|
||||
#iq{type = get,
|
||||
sub_els = [#offline{
|
||||
items = [#offline_item{
|
||||
action = view,
|
||||
node = lists:nth(2, Nodes)},
|
||||
#offline_item{
|
||||
action = view,
|
||||
node = lists:nth(4, Nodes)}]}]}),
|
||||
lists:foreach(
|
||||
fun({I, N}) ->
|
||||
Text = jlib:integer_to_binary(I),
|
||||
?recv1(#message{body = [#text{data = Text}], sub_els = SubEls}),
|
||||
#offline{items = [#offline_item{node = N}]} =
|
||||
lists:keyfind(offline, 1, SubEls)
|
||||
end, lists:zip([2, 4], [lists:nth(2, Nodes), lists:nth(4, Nodes)])),
|
||||
?recv1(#iq{type = result, id = I1, sub_els = []}),
|
||||
%% Delete 2nd and 4th message
|
||||
#iq{type = result, sub_els = []} =
|
||||
send_recv(
|
||||
Config,
|
||||
#iq{type = set,
|
||||
sub_els = [#offline{
|
||||
items = [#offline_item{
|
||||
action = remove,
|
||||
node = lists:nth(2, Nodes)},
|
||||
#offline_item{
|
||||
action = remove,
|
||||
node = lists:nth(4, Nodes)}]}]}),
|
||||
%% Check if messages were deleted
|
||||
#iq{type = result,
|
||||
sub_els = [#disco_items{
|
||||
node = ?NS_FLEX_OFFLINE,
|
||||
items = RemainedItems}]} =
|
||||
send_recv(Config, #iq{type = get,
|
||||
sub_els = [#disco_items{
|
||||
node = ?NS_FLEX_OFFLINE}]}),
|
||||
RemainedNodes = [lists:nth(1, Nodes),
|
||||
lists:nth(3, Nodes),
|
||||
lists:nth(5, Nodes)],
|
||||
RemainedNodes = lists:sort(
|
||||
lists:map(
|
||||
fun(#disco_item{node = N}) -> N end,
|
||||
RemainedItems)),
|
||||
%% Purge everything left
|
||||
#iq{type = result, sub_els = []} =
|
||||
send_recv(Config, #iq{type = set, sub_els = [#offline{purge = true}]}),
|
||||
%% Check if there is no offline messages
|
||||
#iq{type = result,
|
||||
sub_els = [#disco_items{node = ?NS_FLEX_OFFLINE, items = []}]} =
|
||||
send_recv(Config, #iq{type = get,
|
||||
sub_els = [#disco_items{
|
||||
node = ?NS_FLEX_OFFLINE}]}),
|
||||
disconnect(Config).
|
||||
|
||||
offline_master(Config) ->
|
||||
Peer = ?config(slave, Config),
|
||||
LPeer = jlib:jid_remove_resource(Peer),
|
||||
|
@ -1,4 +1,4 @@
|
||||
%% Created automatically by XML generator (xml_gen.erl)
|
||||
%% Created automatically by XML generator (fxml_gen.erl)
|
||||
%% Source: xmpp_codec.spec
|
||||
|
||||
-module(xmpp_codec).
|
||||
@ -15,6 +15,22 @@ decode(_el) -> decode(_el, []).
|
||||
decode({xmlel, _name, _attrs, _} = _el, Opts) ->
|
||||
IgnoreEls = proplists:get_bool(ignore_els, Opts),
|
||||
case {_name, get_attr(<<"xmlns">>, _attrs)} of
|
||||
{<<"offline">>,
|
||||
<<"http://jabber.org/protocol/offline">>} ->
|
||||
decode_offline(<<"http://jabber.org/protocol/offline">>,
|
||||
IgnoreEls, _el);
|
||||
{<<"item">>,
|
||||
<<"http://jabber.org/protocol/offline">>} ->
|
||||
decode_offline_item(<<"http://jabber.org/protocol/offline">>,
|
||||
IgnoreEls, _el);
|
||||
{<<"fetch">>,
|
||||
<<"http://jabber.org/protocol/offline">>} ->
|
||||
decode_offline_fetch(<<"http://jabber.org/protocol/offline">>,
|
||||
IgnoreEls, _el);
|
||||
{<<"purge">>,
|
||||
<<"http://jabber.org/protocol/offline">>} ->
|
||||
decode_offline_purge(<<"http://jabber.org/protocol/offline">>,
|
||||
IgnoreEls, _el);
|
||||
{<<"failed">>, <<"urn:xmpp:sm:2">>} ->
|
||||
decode_sm_failed(<<"urn:xmpp:sm:2">>, IgnoreEls, _el);
|
||||
{<<"failed">>, <<"urn:xmpp:sm:3">>} ->
|
||||
@ -1072,6 +1088,18 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) ->
|
||||
|
||||
is_known_tag({xmlel, _name, _attrs, _} = _el) ->
|
||||
case {_name, get_attr(<<"xmlns">>, _attrs)} of
|
||||
{<<"offline">>,
|
||||
<<"http://jabber.org/protocol/offline">>} ->
|
||||
true;
|
||||
{<<"item">>,
|
||||
<<"http://jabber.org/protocol/offline">>} ->
|
||||
true;
|
||||
{<<"fetch">>,
|
||||
<<"http://jabber.org/protocol/offline">>} ->
|
||||
true;
|
||||
{<<"purge">>,
|
||||
<<"http://jabber.org/protocol/offline">>} ->
|
||||
true;
|
||||
{<<"failed">>, <<"urn:xmpp:sm:2">>} -> true;
|
||||
{<<"failed">>, <<"urn:xmpp:sm:3">>} -> true;
|
||||
{<<"a">>, <<"urn:xmpp:sm:2">>} -> true;
|
||||
@ -2124,7 +2152,15 @@ encode({sm_resumed, _, _, _} = Resumed) ->
|
||||
encode({sm_r, _} = R) -> encode_sm_r(R, []);
|
||||
encode({sm_a, _, _} = A) -> encode_sm_a(A, []);
|
||||
encode({sm_failed, _, _} = Failed) ->
|
||||
encode_sm_failed(Failed, []).
|
||||
encode_sm_failed(Failed, []);
|
||||
encode({offline_item, _, _} = Item) ->
|
||||
encode_offline_item(Item,
|
||||
[{<<"xmlns">>,
|
||||
<<"http://jabber.org/protocol/offline">>}]);
|
||||
encode({offline, _, _, _} = Offline) ->
|
||||
encode_offline(Offline,
|
||||
[{<<"xmlns">>,
|
||||
<<"http://jabber.org/protocol/offline">>}]).
|
||||
|
||||
get_ns({last, _, _}) -> <<"jabber:iq:last">>;
|
||||
get_ns({version, _, _, _}) -> <<"jabber:iq:version">>;
|
||||
@ -2319,6 +2355,10 @@ get_ns({carbons_sent, _}) -> <<"urn:xmpp:carbons:2">>;
|
||||
get_ns({feature_csi, _}) -> <<"urn:xmpp:csi:0">>;
|
||||
get_ns({csi, active}) -> <<"urn:xmpp:csi:0">>;
|
||||
get_ns({csi, inactive}) -> <<"urn:xmpp:csi:0">>;
|
||||
get_ns({offline_item, _, _}) ->
|
||||
<<"http://jabber.org/protocol/offline">>;
|
||||
get_ns({offline, _, _, _}) ->
|
||||
<<"http://jabber.org/protocol/offline">>;
|
||||
get_ns(_) -> <<>>.
|
||||
|
||||
dec_int(Val) -> dec_int(Val, infinity, infinity).
|
||||
@ -2522,6 +2562,8 @@ pp(sm_resumed, 3) -> [h, previd, xmlns];
|
||||
pp(sm_r, 1) -> [xmlns];
|
||||
pp(sm_a, 2) -> [h, xmlns];
|
||||
pp(sm_failed, 2) -> [reason, xmlns];
|
||||
pp(offline_item, 2) -> [node, action];
|
||||
pp(offline, 3) -> [items, purge, fetch];
|
||||
pp(_, _) -> no.
|
||||
|
||||
enc_bool(false) -> <<"false">>;
|
||||
@ -2564,6 +2606,156 @@ dec_tzo(Val) ->
|
||||
M = jlib:binary_to_integer(M1),
|
||||
if H >= -12, H =< 12, M >= 0, M < 60 -> {H, M} end.
|
||||
|
||||
decode_offline(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"offline">>, _attrs, _els}) ->
|
||||
{Items, Purge, Fetch} = decode_offline_els(__TopXMLNS,
|
||||
__IgnoreEls, _els, [], false,
|
||||
false),
|
||||
{offline, Items, Purge, Fetch}.
|
||||
|
||||
decode_offline_els(__TopXMLNS, __IgnoreEls, [], Items,
|
||||
Purge, Fetch) ->
|
||||
{lists:reverse(Items), Purge, Fetch};
|
||||
decode_offline_els(__TopXMLNS, __IgnoreEls,
|
||||
[{xmlel, <<"purge">>, _attrs, _} = _el | _els], Items,
|
||||
Purge, Fetch) ->
|
||||
_xmlns = get_attr(<<"xmlns">>, _attrs),
|
||||
if _xmlns == <<>>; _xmlns == __TopXMLNS ->
|
||||
decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items,
|
||||
decode_offline_purge(__TopXMLNS, __IgnoreEls,
|
||||
_el),
|
||||
Fetch);
|
||||
true ->
|
||||
decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items,
|
||||
Purge, Fetch)
|
||||
end;
|
||||
decode_offline_els(__TopXMLNS, __IgnoreEls,
|
||||
[{xmlel, <<"fetch">>, _attrs, _} = _el | _els], Items,
|
||||
Purge, Fetch) ->
|
||||
_xmlns = get_attr(<<"xmlns">>, _attrs),
|
||||
if _xmlns == <<>>; _xmlns == __TopXMLNS ->
|
||||
decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items,
|
||||
Purge,
|
||||
decode_offline_fetch(__TopXMLNS, __IgnoreEls,
|
||||
_el));
|
||||
true ->
|
||||
decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items,
|
||||
Purge, Fetch)
|
||||
end;
|
||||
decode_offline_els(__TopXMLNS, __IgnoreEls,
|
||||
[{xmlel, <<"item">>, _attrs, _} = _el | _els], Items,
|
||||
Purge, Fetch) ->
|
||||
_xmlns = get_attr(<<"xmlns">>, _attrs),
|
||||
if _xmlns == <<>>; _xmlns == __TopXMLNS ->
|
||||
decode_offline_els(__TopXMLNS, __IgnoreEls, _els,
|
||||
[decode_offline_item(__TopXMLNS, __IgnoreEls, _el)
|
||||
| Items],
|
||||
Purge, Fetch);
|
||||
true ->
|
||||
decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items,
|
||||
Purge, Fetch)
|
||||
end;
|
||||
decode_offline_els(__TopXMLNS, __IgnoreEls, [_ | _els],
|
||||
Items, Purge, Fetch) ->
|
||||
decode_offline_els(__TopXMLNS, __IgnoreEls, _els, Items,
|
||||
Purge, Fetch).
|
||||
|
||||
encode_offline({offline, Items, Purge, Fetch},
|
||||
_xmlns_attrs) ->
|
||||
_els = lists:reverse('encode_offline_$items'(Items,
|
||||
'encode_offline_$purge'(Purge,
|
||||
'encode_offline_$fetch'(Fetch,
|
||||
[])))),
|
||||
_attrs = _xmlns_attrs,
|
||||
{xmlel, <<"offline">>, _attrs, _els}.
|
||||
|
||||
'encode_offline_$items'([], _acc) -> _acc;
|
||||
'encode_offline_$items'([Items | _els], _acc) ->
|
||||
'encode_offline_$items'(_els,
|
||||
[encode_offline_item(Items, []) | _acc]).
|
||||
|
||||
'encode_offline_$purge'(false, _acc) -> _acc;
|
||||
'encode_offline_$purge'(Purge, _acc) ->
|
||||
[encode_offline_purge(Purge, []) | _acc].
|
||||
|
||||
'encode_offline_$fetch'(false, _acc) -> _acc;
|
||||
'encode_offline_$fetch'(Fetch, _acc) ->
|
||||
[encode_offline_fetch(Fetch, []) | _acc].
|
||||
|
||||
decode_offline_item(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"item">>, _attrs, _els}) ->
|
||||
{Node, Action} = decode_offline_item_attrs(__TopXMLNS,
|
||||
_attrs, undefined, undefined),
|
||||
{offline_item, Node, Action}.
|
||||
|
||||
decode_offline_item_attrs(__TopXMLNS,
|
||||
[{<<"node">>, _val} | _attrs], _Node, Action) ->
|
||||
decode_offline_item_attrs(__TopXMLNS, _attrs, _val,
|
||||
Action);
|
||||
decode_offline_item_attrs(__TopXMLNS,
|
||||
[{<<"action">>, _val} | _attrs], Node, _Action) ->
|
||||
decode_offline_item_attrs(__TopXMLNS, _attrs, Node,
|
||||
_val);
|
||||
decode_offline_item_attrs(__TopXMLNS, [_ | _attrs],
|
||||
Node, Action) ->
|
||||
decode_offline_item_attrs(__TopXMLNS, _attrs, Node,
|
||||
Action);
|
||||
decode_offline_item_attrs(__TopXMLNS, [], Node,
|
||||
Action) ->
|
||||
{decode_offline_item_attr_node(__TopXMLNS, Node),
|
||||
decode_offline_item_attr_action(__TopXMLNS, Action)}.
|
||||
|
||||
encode_offline_item({offline_item, Node, Action},
|
||||
_xmlns_attrs) ->
|
||||
_els = [],
|
||||
_attrs = encode_offline_item_attr_action(Action,
|
||||
encode_offline_item_attr_node(Node,
|
||||
_xmlns_attrs)),
|
||||
{xmlel, <<"item">>, _attrs, _els}.
|
||||
|
||||
decode_offline_item_attr_node(__TopXMLNS, undefined) ->
|
||||
undefined;
|
||||
decode_offline_item_attr_node(__TopXMLNS, _val) -> _val.
|
||||
|
||||
encode_offline_item_attr_node(undefined, _acc) -> _acc;
|
||||
encode_offline_item_attr_node(_val, _acc) ->
|
||||
[{<<"node">>, _val} | _acc].
|
||||
|
||||
decode_offline_item_attr_action(__TopXMLNS,
|
||||
undefined) ->
|
||||
undefined;
|
||||
decode_offline_item_attr_action(__TopXMLNS, _val) ->
|
||||
case catch dec_enum(_val, [view, remove]) of
|
||||
{'EXIT', _} ->
|
||||
erlang:error({xmpp_codec,
|
||||
{bad_attr_value, <<"action">>, <<"item">>,
|
||||
__TopXMLNS}});
|
||||
_res -> _res
|
||||
end.
|
||||
|
||||
encode_offline_item_attr_action(undefined, _acc) ->
|
||||
_acc;
|
||||
encode_offline_item_attr_action(_val, _acc) ->
|
||||
[{<<"action">>, enc_enum(_val)} | _acc].
|
||||
|
||||
decode_offline_fetch(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"fetch">>, _attrs, _els}) ->
|
||||
true.
|
||||
|
||||
encode_offline_fetch(true, _xmlns_attrs) ->
|
||||
_els = [],
|
||||
_attrs = _xmlns_attrs,
|
||||
{xmlel, <<"fetch">>, _attrs, _els}.
|
||||
|
||||
decode_offline_purge(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"purge">>, _attrs, _els}) ->
|
||||
true.
|
||||
|
||||
encode_offline_purge(true, _xmlns_attrs) ->
|
||||
_els = [],
|
||||
_attrs = _xmlns_attrs,
|
||||
{xmlel, <<"purge">>, _attrs, _els}.
|
||||
|
||||
decode_sm_failed(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"failed">>, _attrs, _els}) ->
|
||||
Reason = decode_sm_failed_els(__TopXMLNS, __IgnoreEls,
|
||||
|
@ -1,4 +1,4 @@
|
||||
%% Created automatically by XML generator (xml_gen.erl)
|
||||
%% Created automatically by XML generator (fxml_gen.erl)
|
||||
%% Source: xmpp_codec.spec
|
||||
|
||||
-record(chatstate, {type :: active | composing | gone | inactive | paused}).
|
||||
@ -424,6 +424,13 @@
|
||||
features = [] :: [binary()],
|
||||
xdata = [] :: [#xdata{}]}).
|
||||
|
||||
-record(offline_item, {node :: binary(),
|
||||
action :: 'remove' | 'view'}).
|
||||
|
||||
-record(offline, {items = [] :: [#offline_item{}],
|
||||
purge = false :: boolean(),
|
||||
fetch = false :: boolean()}).
|
||||
|
||||
-record(sasl_mechanisms, {list = [] :: [binary()]}).
|
||||
|
||||
-record(sm_failed, {reason :: atom() | #gone{} | #redirect{},
|
||||
|
@ -2398,6 +2398,35 @@
|
||||
#ref{name = error_unexpected_request,
|
||||
min = 0, max = 1, label = '$reason'}]}).
|
||||
|
||||
-xml(offline_purge,
|
||||
#elem{name = <<"purge">>,
|
||||
xmlns = <<"http://jabber.org/protocol/offline">>,
|
||||
result = true}).
|
||||
|
||||
-xml(offline_fetch,
|
||||
#elem{name = <<"fetch">>,
|
||||
xmlns = <<"http://jabber.org/protocol/offline">>,
|
||||
result = true}).
|
||||
|
||||
-xml(offline_item,
|
||||
#elem{name = <<"item">>,
|
||||
xmlns = <<"http://jabber.org/protocol/offline">>,
|
||||
result = {offline_item, '$node', '$action'},
|
||||
attrs = [#attr{name = <<"node">>},
|
||||
#attr{name = <<"action">>,
|
||||
dec = {dec_enum, [[view, remove]]},
|
||||
enc = {enc_enum, []}}]}).
|
||||
|
||||
-xml(offline,
|
||||
#elem{name = <<"offline">>,
|
||||
xmlns = <<"http://jabber.org/protocol/offline">>,
|
||||
result = {offline, '$items', '$purge', '$fetch'},
|
||||
refs = [#ref{name = offline_purge, min = 0, max = 1,
|
||||
label = '$purge', default = false},
|
||||
#ref{name = offline_fetch, min = 0, max = 1,
|
||||
label = '$fetch', default = false},
|
||||
#ref{name = offline_item, min = 0, label = '$items'}]}).
|
||||
|
||||
dec_tzo(Val) ->
|
||||
[H1, M1] = str:tokens(Val, <<":">>),
|
||||
H = jlib:binary_to_integer(H1),
|
||||
|
Loading…
Reference in New Issue
Block a user