mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
Rewrite mod_offline to use XML generator
This commit is contained in:
parent
9a8e197d7e
commit
a4a9dd7f03
@ -11,7 +11,8 @@
|
||||
-record(csi, {type :: active | inactive}).
|
||||
-type csi() :: #csi{}.
|
||||
|
||||
-record(hint, {type :: 'no-copy' | 'no-store' | 'store' | 'no-permanent-store'}).
|
||||
-record(hint, {type :: 'no-copy' | 'no-store' | 'no-storage' |
|
||||
'store' | 'no-permanent-store'}).
|
||||
-type hint() :: #hint{}.
|
||||
|
||||
-record(feature_register, {}).
|
||||
@ -50,6 +51,10 @@
|
||||
-record(carbons_private, {}).
|
||||
-type carbons_private() :: #carbons_private{}.
|
||||
|
||||
-record(expire, {seconds :: non_neg_integer(),
|
||||
stored :: non_neg_integer()}).
|
||||
-type expire() :: #expire{}.
|
||||
|
||||
-record(pubsub_unsubscribe, {node :: binary(),
|
||||
jid :: any(),
|
||||
subid :: binary()}).
|
||||
@ -304,6 +309,13 @@
|
||||
-record(sasl_abort, {}).
|
||||
-type sasl_abort() :: #sasl_abort{}.
|
||||
|
||||
-record(xevent, {offline = false :: boolean(),
|
||||
delivered = false :: boolean(),
|
||||
displayed = false :: boolean(),
|
||||
composing = false :: boolean(),
|
||||
id :: binary()}).
|
||||
-type xevent() :: #xevent{}.
|
||||
|
||||
-record(vcard_email, {home = false :: boolean(),
|
||||
work = false :: boolean(),
|
||||
internet = false :: boolean(),
|
||||
@ -717,6 +729,7 @@
|
||||
starttls_proceed() |
|
||||
sm_resumed() |
|
||||
forwarded() |
|
||||
xevent() |
|
||||
privacy_list() |
|
||||
text() |
|
||||
vcard_org() |
|
||||
@ -735,12 +748,12 @@
|
||||
pubsub_options() |
|
||||
compress() |
|
||||
bytestreams() |
|
||||
muc_history() |
|
||||
identity() |
|
||||
feature_csi() |
|
||||
muc_user_destroy() |
|
||||
privacy_query() |
|
||||
delay() |
|
||||
muc_history() |
|
||||
vcard_tel() |
|
||||
vcard_logo() |
|
||||
disco_info() |
|
||||
@ -780,6 +793,7 @@
|
||||
vcard_name() |
|
||||
sm_resume() |
|
||||
carbons_enable() |
|
||||
expire() |
|
||||
pubsub_unsubscribe() |
|
||||
muc_decline() |
|
||||
chatstate() |
|
||||
|
@ -49,7 +49,7 @@
|
||||
get_sm_identity/5,
|
||||
get_sm_items/5,
|
||||
get_info/5,
|
||||
handle_offline_query/3,
|
||||
handle_offline_query/1,
|
||||
remove_expired_messages/1,
|
||||
remove_old_messages/2,
|
||||
remove_user/2,
|
||||
@ -73,7 +73,7 @@
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("jlib.hrl").
|
||||
-include("xmpp.hrl").
|
||||
|
||||
-include("ejabberd_http.hrl").
|
||||
|
||||
@ -250,7 +250,7 @@ receive_all(US, Msgs, DBType) ->
|
||||
end
|
||||
end.
|
||||
|
||||
get_sm_features(Acc, _From, _To, <<"">>, _Lang) ->
|
||||
get_sm_features(Acc, _From, _To, undefined, _Lang) ->
|
||||
Feats = case Acc of
|
||||
{result, I} -> I;
|
||||
_ -> []
|
||||
@ -268,12 +268,10 @@ get_sm_features(_Acc, #jid{luser = U, lserver = S}, #jid{luser = U, lserver = S}
|
||||
get_sm_features(Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc.
|
||||
|
||||
get_sm_identity(_Acc, #jid{luser = U, lserver = S}, #jid{luser = U, lserver = S},
|
||||
get_sm_identity(Acc, #jid{luser = U, lserver = S}, #jid{luser = U, lserver = S},
|
||||
?NS_FLEX_OFFLINE, _Lang) ->
|
||||
Identity = #xmlel{name = <<"identity">>,
|
||||
attrs = [{<<"category">>, <<"automation">>},
|
||||
{<<"type">>, <<"message-list">>}]},
|
||||
[Identity];
|
||||
[#identity{category = <<"automation">>,
|
||||
type = <<"message-list">>}|Acc];
|
||||
get_sm_identity(Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc.
|
||||
|
||||
@ -282,15 +280,16 @@ get_sm_items(_Acc, #jid{luser = U, lserver = S, lresource = R} = JID,
|
||||
?NS_FLEX_OFFLINE, _Lang) ->
|
||||
case ejabberd_sm:get_session_pid(U, S, R) of
|
||||
Pid when is_pid(Pid) ->
|
||||
Hdrs = read_message_headers(U, S),
|
||||
BareJID = jid:to_string(jid:remove_resource(JID)),
|
||||
Mod = gen_mod:db_mod(S, ?MODULE),
|
||||
Hdrs = Mod:read_message_headers(U, S),
|
||||
BareJID = jid:remove_resource(JID),
|
||||
Pid ! dont_ask_offline,
|
||||
{result, lists:map(
|
||||
fun({Node, From, _To, _El}) ->
|
||||
#xmlel{name = <<"item">>,
|
||||
attrs = [{<<"jid">>, BareJID},
|
||||
{<<"node">>, Node},
|
||||
{<<"name">>, jid:to_string(From)}]}
|
||||
fun({Seq, From, _To, _El}) ->
|
||||
Node = integer_to_binary(Seq),
|
||||
#disco_item{jid = BareJID,
|
||||
node = Node,
|
||||
name = jid:to_string(From)}
|
||||
end, Hdrs)};
|
||||
none ->
|
||||
{result, []}
|
||||
@ -298,6 +297,8 @@ get_sm_items(_Acc, #jid{luser = U, lserver = S, lresource = R} = JID,
|
||||
get_sm_items(Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc.
|
||||
|
||||
-spec get_info([xdata()], jid(), jid(),
|
||||
undefined | binary(), undefined | binary()) -> [xdata()].
|
||||
get_info(_Acc, #jid{luser = U, lserver = S, lresource = R},
|
||||
#jid{luser = U, lserver = S}, ?NS_FLEX_OFFLINE, _Lang) ->
|
||||
N = jlib:integer_to_binary(count_offline_messages(U, S)),
|
||||
@ -307,50 +308,42 @@ get_info(_Acc, #jid{luser = U, lserver = S, lresource = R},
|
||||
none ->
|
||||
ok
|
||||
end,
|
||||
[#xmlel{name = <<"x">>,
|
||||
attrs = [{<<"xmlns">>, ?NS_XDATA},
|
||||
{<<"type">>, <<"result">>}],
|
||||
children = [#xmlel{name = <<"field">>,
|
||||
attrs = [{<<"var">>, <<"FORM_TYPE">>},
|
||||
{<<"type">>, <<"hidden">>}],
|
||||
children = [#xmlel{name = <<"value">>,
|
||||
children = [{xmlcdata,
|
||||
?NS_FLEX_OFFLINE}]}]},
|
||||
#xmlel{name = <<"field">>,
|
||||
attrs = [{<<"var">>, <<"number_of_messages">>}],
|
||||
children = [#xmlel{name = <<"value">>,
|
||||
children = [{xmlcdata, N}]}]}]}];
|
||||
[#xdata{type = result,
|
||||
fields = [#xdata_field{var = <<"FORM_TYPE">>,
|
||||
type = hidden,
|
||||
values = [?NS_FLEX_OFFLINE]},
|
||||
#xdata_field{var = <<"number_of_messages">>,
|
||||
values = [N]}]}];
|
||||
get_info(Acc, _From, _To, _Node, _Lang) ->
|
||||
Acc.
|
||||
|
||||
handle_offline_query(#jid{luser = U, lserver = S} = From,
|
||||
#jid{luser = U, lserver = S} = _To,
|
||||
#iq{type = Type, sub_el = SubEl} = IQ) ->
|
||||
-spec handle_offline_query(iq()) -> iq().
|
||||
handle_offline_query(#iq{from = #jid{luser = U, lserver = S} = From,
|
||||
to = #jid{luser = U, lserver = S} = _To,
|
||||
type = Type,
|
||||
sub_els = [#offline{purge = Purge,
|
||||
items = Items,
|
||||
fetch = Fetch}]} = IQ) ->
|
||||
case Type of
|
||||
get ->
|
||||
case fxml:get_subtag(SubEl, <<"fetch">>) of
|
||||
#xmlel{} ->
|
||||
handle_offline_fetch(From);
|
||||
false ->
|
||||
handle_offline_items_view(From, SubEl)
|
||||
if Fetch -> handle_offline_fetch(From);
|
||||
true -> handle_offline_items_view(From, Items)
|
||||
end;
|
||||
set ->
|
||||
case fxml:get_subtag(SubEl, <<"purge">>) of
|
||||
#xmlel{} ->
|
||||
delete_all_msgs(U, S);
|
||||
false ->
|
||||
handle_offline_items_remove(From, SubEl)
|
||||
if Purge -> delete_all_msgs(U, S);
|
||||
true -> handle_offline_items_remove(From, Items)
|
||||
end
|
||||
end,
|
||||
IQ#iq{type = result, sub_el = []};
|
||||
handle_offline_query(_From, _To, #iq{sub_el = SubEl, lang = Lang} = IQ) ->
|
||||
xmpp:make_iq_result(IQ);
|
||||
handle_offline_query(#iq{lang = Lang} = IQ) ->
|
||||
Txt = <<"Query to another users is forbidden">>,
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERRT_FORBIDDEN(Lang, Txt)]}.
|
||||
xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang)).
|
||||
|
||||
handle_offline_items_view(JID, #xmlel{children = Items}) ->
|
||||
-spec handle_offline_items_view(jid(), [offline_item()]) -> ok.
|
||||
handle_offline_items_view(JID, Items) ->
|
||||
{U, S, R} = jid:tolower(JID),
|
||||
lists:foreach(
|
||||
fun(Node) ->
|
||||
fun(#offline_item{node = Node, action = view}) ->
|
||||
case fetch_msg_by_node(JID, Node) of
|
||||
{ok, OfflineMsg} ->
|
||||
case offline_msg_to_route(S, OfflineMsg) of
|
||||
@ -367,40 +360,25 @@ handle_offline_items_view(JID, #xmlel{children = Items}) ->
|
||||
end;
|
||||
error ->
|
||||
ok
|
||||
end
|
||||
end, get_nodes_from_items(Items, <<"view">>)).
|
||||
|
||||
handle_offline_items_remove(JID, #xmlel{children = Items}) ->
|
||||
lists:foreach(
|
||||
fun(Node) ->
|
||||
remove_msg_by_node(JID, Node)
|
||||
end, get_nodes_from_items(Items, <<"remove">>)).
|
||||
|
||||
get_nodes_from_items(Items, Action) ->
|
||||
lists:flatmap(
|
||||
fun(#xmlel{name = <<"item">>, attrs = Attrs}) ->
|
||||
case fxml:get_attr_s(<<"action">>, Attrs) of
|
||||
Action ->
|
||||
case fxml:get_attr_s(<<"node">>, Attrs) of
|
||||
<<"">> ->
|
||||
[];
|
||||
TS ->
|
||||
[TS]
|
||||
end;
|
||||
_ ->
|
||||
[]
|
||||
end;
|
||||
(_) ->
|
||||
[]
|
||||
ok
|
||||
end, Items).
|
||||
|
||||
set_offline_tag(#xmlel{children = Els} = El, Node) ->
|
||||
OfflineEl = #xmlel{name = <<"offline">>,
|
||||
attrs = [{<<"xmlns">>, ?NS_FLEX_OFFLINE}],
|
||||
children = [#xmlel{name = <<"item">>,
|
||||
attrs = [{<<"node">>, Node}]}]},
|
||||
El#xmlel{children = [OfflineEl|Els]}.
|
||||
-spec handle_offline_items_remove(jid(), [offline_item()]) -> ok.
|
||||
handle_offline_items_remove(JID, Items) ->
|
||||
lists:foreach(
|
||||
fun(#offline_item{node = Node, action = remove}) ->
|
||||
remove_msg_by_node(JID, Node);
|
||||
(_) ->
|
||||
ok
|
||||
end, Items).
|
||||
|
||||
-spec set_offline_tag(message(), binary()) -> message().
|
||||
set_offline_tag(Msg, Node) ->
|
||||
xmpp:set_subtag(Msg, #offline{items = [#offline_item{node = Node}]}).
|
||||
|
||||
-spec handle_offline_fetch(jid()) -> ok.
|
||||
handle_offline_fetch(#jid{luser = U, lserver = S, lresource = R}) ->
|
||||
case ejabberd_sm:get_session_pid(U, S, R) of
|
||||
none ->
|
||||
@ -414,6 +392,7 @@ handle_offline_fetch(#jid{luser = U, lserver = S, lresource = R}) ->
|
||||
end, read_message_headers(U, S))
|
||||
end.
|
||||
|
||||
-spec fetch_msg_by_node(jid(), binary()) -> error | {ok, #offline_msg{}}.
|
||||
fetch_msg_by_node(To, Seq) ->
|
||||
case catch binary_to_integer(Seq) of
|
||||
I when is_integer(I), I >= 0 ->
|
||||
@ -425,6 +404,7 @@ fetch_msg_by_node(To, Seq) ->
|
||||
error
|
||||
end.
|
||||
|
||||
-spec remove_msg_by_node(jid(), binary()) -> ok.
|
||||
remove_msg_by_node(To, Seq) ->
|
||||
case catch binary_to_integer(Seq) of
|
||||
I when is_integer(I), I>= 0 ->
|
||||
@ -436,39 +416,38 @@ remove_msg_by_node(To, Seq) ->
|
||||
ok
|
||||
end.
|
||||
|
||||
-spec need_to_store(binary(), message()) -> boolean().
|
||||
need_to_store(_LServer, #message{type = error}) -> false;
|
||||
need_to_store(_LServer, #message{type = groupchat}) -> false;
|
||||
need_to_store(_LServer, #message{type = headline}) -> false;
|
||||
need_to_store(LServer, Packet) ->
|
||||
Type = fxml:get_tag_attr_s(<<"type">>, Packet),
|
||||
if (Type /= <<"error">>) and (Type /= <<"groupchat">>)
|
||||
and (Type /= <<"headline">>) ->
|
||||
case has_offline_tag(Packet) of
|
||||
false ->
|
||||
case check_store_hint(Packet) of
|
||||
store ->
|
||||
true;
|
||||
no_store ->
|
||||
false;
|
||||
none ->
|
||||
case gen_mod:get_module_opt(
|
||||
LServer, ?MODULE, store_empty_body,
|
||||
fun(V) when is_boolean(V) -> V;
|
||||
(unless_chat_state) -> unless_chat_state
|
||||
end,
|
||||
unless_chat_state) of
|
||||
false ->
|
||||
fxml:get_subtag(Packet, <<"body">>) /= false;
|
||||
unless_chat_state ->
|
||||
not jlib:is_standalone_chat_state(Packet);
|
||||
true ->
|
||||
true
|
||||
end
|
||||
end;
|
||||
true ->
|
||||
false
|
||||
case xmpp:has_subtag(Packet, #offline{}) of
|
||||
false ->
|
||||
case check_store_hint(Packet) of
|
||||
store ->
|
||||
true;
|
||||
no_store ->
|
||||
false;
|
||||
none ->
|
||||
case gen_mod:get_module_opt(
|
||||
LServer, ?MODULE, store_empty_body,
|
||||
fun(V) when is_boolean(V) -> V;
|
||||
(unless_chat_state) -> unless_chat_state
|
||||
end,
|
||||
unless_chat_state) of
|
||||
false ->
|
||||
Packet#message.body /= [];
|
||||
unless_chat_state ->
|
||||
not xmpp_util:is_standalone_chat_state(Packet);
|
||||
true ->
|
||||
true
|
||||
end
|
||||
end;
|
||||
true ->
|
||||
true ->
|
||||
false
|
||||
end.
|
||||
|
||||
-spec store_packet(jid(), jid(), message()) -> ok | stop.
|
||||
store_packet(From, To, Packet) ->
|
||||
case need_to_store(To#jid.lserver, Packet) of
|
||||
true ->
|
||||
@ -476,18 +455,19 @@ store_packet(From, To, Packet) ->
|
||||
true ->
|
||||
#jid{luser = LUser, lserver = LServer} = To,
|
||||
TimeStamp = p1_time_compat:timestamp(),
|
||||
#xmlel{children = Els} = Packet,
|
||||
Expire = find_x_expire(TimeStamp, Els),
|
||||
Expire = find_x_expire(TimeStamp, Packet),
|
||||
El = xmpp:encode(Packet),
|
||||
gen_mod:get_module_proc(To#jid.lserver, ?PROCNAME) !
|
||||
#offline_msg{us = {LUser, LServer},
|
||||
timestamp = TimeStamp, expire = Expire,
|
||||
from = From, to = To, packet = Packet},
|
||||
from = From, to = To, packet = El},
|
||||
stop;
|
||||
_ -> ok
|
||||
end;
|
||||
false -> ok
|
||||
end.
|
||||
|
||||
-spec check_store_hint(message()) -> store | no_store | none.
|
||||
check_store_hint(Packet) ->
|
||||
case has_store_hint(Packet) of
|
||||
true ->
|
||||
@ -501,89 +481,43 @@ check_store_hint(Packet) ->
|
||||
end
|
||||
end.
|
||||
|
||||
-spec has_store_hint(message()) -> boolean().
|
||||
has_store_hint(Packet) ->
|
||||
fxml:get_subtag_with_xmlns(Packet, <<"store">>, ?NS_HINTS) =/= false.
|
||||
xmpp:has_subtag(Packet, #hint{type = 'store'}).
|
||||
|
||||
-spec has_no_store_hint(message()) -> boolean().
|
||||
has_no_store_hint(Packet) ->
|
||||
fxml:get_subtag_with_xmlns(Packet, <<"no-store">>, ?NS_HINTS) =/= false
|
||||
orelse
|
||||
fxml:get_subtag_with_xmlns(Packet, <<"no-storage">>, ?NS_HINTS) =/= false.
|
||||
|
||||
has_offline_tag(Packet) ->
|
||||
fxml:get_subtag_with_xmlns(Packet, <<"offline">>, ?NS_FLEX_OFFLINE) =/= false.
|
||||
xmpp:has_subtag(Packet, #hint{type = 'no-store'})
|
||||
orelse
|
||||
xmpp:has_subtag(Packet, #hint{type = 'no-storage'}).
|
||||
|
||||
%% Check if the packet has any content about XEP-0022
|
||||
check_event(From, To, Packet) ->
|
||||
#xmlel{name = Name, attrs = Attrs, children = Els} =
|
||||
Packet,
|
||||
case find_x_event(Els) of
|
||||
false -> true;
|
||||
El ->
|
||||
case fxml:get_subtag(El, <<"id">>) of
|
||||
false ->
|
||||
case fxml:get_subtag(El, <<"offline">>) of
|
||||
false -> true;
|
||||
_ ->
|
||||
ID = case fxml:get_tag_attr_s(<<"id">>, Packet) of
|
||||
<<"">> ->
|
||||
#xmlel{name = <<"id">>, attrs = [],
|
||||
children = []};
|
||||
S ->
|
||||
#xmlel{name = <<"id">>, attrs = [],
|
||||
children = [{xmlcdata, S}]}
|
||||
end,
|
||||
ejabberd_router:route(To, From,
|
||||
#xmlel{name = Name, attrs = Attrs,
|
||||
children =
|
||||
[#xmlel{name = <<"x">>,
|
||||
attrs =
|
||||
[{<<"xmlns">>,
|
||||
?NS_EVENT}],
|
||||
children =
|
||||
[ID,
|
||||
#xmlel{name
|
||||
=
|
||||
<<"offline">>,
|
||||
attrs
|
||||
=
|
||||
[],
|
||||
children
|
||||
=
|
||||
[]}]}]}),
|
||||
true
|
||||
end;
|
||||
_ -> false
|
||||
end
|
||||
-spec check_event(jid(), jid(), message()) -> boolean().
|
||||
check_event(From, To, #message{id = ID} = Msg) ->
|
||||
case xmpp:get_subtag(Msg, #xevent{}) of
|
||||
false ->
|
||||
true;
|
||||
#xevent{id = undefined, offline = false} ->
|
||||
true;
|
||||
#xevent{id = undefined, offline = true} ->
|
||||
NewMsg = Msg#message{sub_els = [#xevent{id = ID, offline = true}]},
|
||||
ejabberd_router:route(To, From, xmpp:set_from_to(NewMsg, To, From)),
|
||||
true;
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
%% Check if the packet has subelements about XEP-0022
|
||||
find_x_event([]) -> false;
|
||||
find_x_event([{xmlcdata, _} | Els]) ->
|
||||
find_x_event(Els);
|
||||
find_x_event([El | Els]) ->
|
||||
case fxml:get_tag_attr_s(<<"xmlns">>, El) of
|
||||
?NS_EVENT -> El;
|
||||
_ -> find_x_event(Els)
|
||||
end.
|
||||
|
||||
find_x_expire(_, []) -> never;
|
||||
find_x_expire(TimeStamp, [{xmlcdata, _} | Els]) ->
|
||||
find_x_expire(TimeStamp, Els);
|
||||
find_x_expire(TimeStamp, [El | Els]) ->
|
||||
case fxml:get_tag_attr_s(<<"xmlns">>, El) of
|
||||
?NS_EXPIRE ->
|
||||
Val = fxml:get_tag_attr_s(<<"seconds">>, El),
|
||||
case catch jlib:binary_to_integer(Val) of
|
||||
{'EXIT', _} -> never;
|
||||
Int when Int > 0 ->
|
||||
{MegaSecs, Secs, MicroSecs} = TimeStamp,
|
||||
S = MegaSecs * 1000000 + Secs + Int,
|
||||
MegaSecs1 = S div 1000000,
|
||||
Secs1 = S rem 1000000,
|
||||
{MegaSecs1, Secs1, MicroSecs};
|
||||
_ -> never
|
||||
end;
|
||||
_ -> find_x_expire(TimeStamp, Els)
|
||||
-spec find_x_expire(erlang:timestamp(), message()) -> erlang:timestamp() | never.
|
||||
find_x_expire(TimeStamp, Msg) ->
|
||||
case xmpp:get_subtag(Msg, #expire{}) of
|
||||
#expire{seconds = Int} ->
|
||||
{MegaSecs, Secs, MicroSecs} = TimeStamp,
|
||||
S = MegaSecs * 1000000 + Secs + Int,
|
||||
MegaSecs1 = S div 1000000,
|
||||
Secs1 = S rem 1000000,
|
||||
{MegaSecs1, Secs1, MicroSecs};
|
||||
false ->
|
||||
never
|
||||
end.
|
||||
|
||||
resend_offline_messages(User, Server) ->
|
||||
@ -612,10 +546,9 @@ pop_offline_messages(Ls, User, Server) ->
|
||||
end,
|
||||
lists:filter(
|
||||
fun(#offline_msg{packet = Pkt} = R) ->
|
||||
#xmlel{children = Els} = Pkt,
|
||||
Expire = case R#offline_msg.expire of
|
||||
undefined ->
|
||||
find_x_expire(TS, Els);
|
||||
find_x_expire(TS, Pkt);
|
||||
Exp ->
|
||||
Exp
|
||||
end,
|
||||
@ -648,17 +581,15 @@ remove_user(User, Server) ->
|
||||
|
||||
%% Warn senders that their messages have been discarded:
|
||||
discard_warn_sender(Msgs) ->
|
||||
lists:foreach(fun (#offline_msg{from = From, to = To,
|
||||
packet = Packet}) ->
|
||||
ErrText = <<"Your contact offline message queue is "
|
||||
"full. The message has been discarded.">>,
|
||||
Lang = fxml:get_tag_attr_s(<<"xml:lang">>, Packet),
|
||||
Err = jlib:make_error_reply(Packet,
|
||||
?ERRT_RESOURCE_CONSTRAINT(Lang,
|
||||
ErrText)),
|
||||
ejabberd_router:route(To, From, Err)
|
||||
end,
|
||||
Msgs).
|
||||
lists:foreach(
|
||||
fun(#offline_msg{from = From, to = To, packet = Packet}) ->
|
||||
ErrText = <<"Your contact offline message queue is "
|
||||
"full. The message has been discarded.">>,
|
||||
Lang = xmpp:get_lang(Packet),
|
||||
Err = xmpp:make_error(
|
||||
Packet, xmpp:err_resource_constraint(ErrText, Lang)),
|
||||
ejabberd_router:route(To, From, Err)
|
||||
end, Msgs).
|
||||
|
||||
webadmin_page(_, Host,
|
||||
#request{us = _US, path = [<<"user">>, U, <<"queue">>],
|
||||
@ -668,29 +599,30 @@ webadmin_page(_, Host,
|
||||
webadmin_page(Acc, _, _) -> Acc.
|
||||
|
||||
get_offline_els(LUser, LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
Hdrs = Mod:read_message_headers(LUser, LServer),
|
||||
Hdrs = read_message_headers(LUser, LServer),
|
||||
lists:map(
|
||||
fun({_Seq, From, To, Packet}) ->
|
||||
jlib:replace_from_to(From, To, Packet)
|
||||
xmpp:set_from_to(Packet, From, To)
|
||||
end, Hdrs).
|
||||
|
||||
offline_msg_to_route(LServer, #offline_msg{} = R) ->
|
||||
El = case R#offline_msg.timestamp of
|
||||
undefined ->
|
||||
R#offline_msg.packet;
|
||||
TS ->
|
||||
jlib:add_delay_info(R#offline_msg.packet, LServer, TS,
|
||||
<<"Offline Storage">>)
|
||||
end,
|
||||
{route, R#offline_msg.from, R#offline_msg.to, El}.
|
||||
Pkt = xmpp:decode(R#offline_msg.packet, [ignore_els]),
|
||||
Pkt1 = case R#offline_msg.timestamp of
|
||||
undefined ->
|
||||
Pkt;
|
||||
TS ->
|
||||
xmpp_util:add_delay_info(Pkt, LServer, TS,
|
||||
<<"Offline Storage">>)
|
||||
end,
|
||||
{route, R#offline_msg.from, R#offline_msg.to, Pkt1}.
|
||||
|
||||
read_message_headers(LUser, LServer) ->
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
lists:map(
|
||||
fun({Seq, From, To, El}) ->
|
||||
Node = integer_to_binary(Seq),
|
||||
{Node, From, To, El}
|
||||
Packet = xmpp:decode(El, [ignore_els]),
|
||||
{Node, From, To, Packet}
|
||||
end, Mod:read_message_headers(LUser, LServer)).
|
||||
|
||||
format_user_queue(Hdrs) ->
|
||||
@ -826,6 +758,7 @@ webadmin_user(Acc, User, Server, Lang) ->
|
||||
?INPUTT(<<"submit">>, <<"removealloffline">>,
|
||||
<<"Remove All Offline Messages">>)].
|
||||
|
||||
-spec delete_all_msgs(binary(), binary()) -> {atomic, any()}.
|
||||
delete_all_msgs(User, Server) ->
|
||||
LUser = jid:nodeprep(User),
|
||||
LServer = jid:nameprep(Server),
|
||||
@ -849,6 +782,7 @@ webadmin_user_parse_query(Acc, _Action, _User, _Server,
|
||||
Acc.
|
||||
|
||||
%% Returns as integer the number of offline messages for a given user
|
||||
-spec count_offline_messages(binary(), binary()) -> non_neg_integer().
|
||||
count_offline_messages(User, Server) ->
|
||||
LUser = jid:nodeprep(User),
|
||||
LServer = jid:nameprep(Server),
|
||||
|
@ -156,10 +156,12 @@ get_error(#iq{error = E}) -> E;
|
||||
get_error(#message{error = E}) -> E;
|
||||
get_error(#presence{error = E}) -> E.
|
||||
|
||||
-spec get_els(iq() | message() | presence()) -> [xmpp_element() | xmlel()].
|
||||
-spec get_els(iq() | message() | presence()) -> [xmpp_element() | xmlel()];
|
||||
(xmlel()) -> [xmlel()].
|
||||
get_els(#iq{sub_els = Els}) -> Els;
|
||||
get_els(#message{sub_els = Els}) -> Els;
|
||||
get_els(#presence{sub_els = Els}) -> Els.
|
||||
get_els(#presence{sub_els = Els}) -> Els;
|
||||
get_els(#xmlel{children = Els}) -> [El || El = #xmlel{} <- Els].
|
||||
|
||||
-spec set_id(iq(), binary()) -> iq();
|
||||
(message(), binary()) -> message();
|
||||
|
@ -15,6 +15,24 @@ decode(_el) -> decode(_el, []).
|
||||
decode({xmlel, _name, _attrs, _} = _el, Opts) ->
|
||||
IgnoreEls = proplists:get_bool(ignore_els, Opts),
|
||||
case {_name, get_attr(<<"xmlns">>, _attrs)} of
|
||||
{<<"x">>, <<"jabber:x:expire">>} ->
|
||||
decode_expire(<<"jabber:x:expire">>, IgnoreEls, _el);
|
||||
{<<"x">>, <<"jabber:x:event">>} ->
|
||||
decode_xevent(<<"jabber:x:event">>, IgnoreEls, _el);
|
||||
{<<"id">>, <<"jabber:x:event">>} ->
|
||||
decode_xevent_id(<<"jabber:x:event">>, IgnoreEls, _el);
|
||||
{<<"composing">>, <<"jabber:x:event">>} ->
|
||||
decode_xevent_composing(<<"jabber:x:event">>, IgnoreEls,
|
||||
_el);
|
||||
{<<"displayed">>, <<"jabber:x:event">>} ->
|
||||
decode_xevent_displayed(<<"jabber:x:event">>, IgnoreEls,
|
||||
_el);
|
||||
{<<"delivered">>, <<"jabber:x:event">>} ->
|
||||
decode_xevent_delivered(<<"jabber:x:event">>, IgnoreEls,
|
||||
_el);
|
||||
{<<"offline">>, <<"jabber:x:event">>} ->
|
||||
decode_xevent_offline(<<"jabber:x:event">>, IgnoreEls,
|
||||
_el);
|
||||
{<<"query">>, <<"jabber:iq:search">>} ->
|
||||
decode_search(<<"jabber:iq:search">>, IgnoreEls, _el);
|
||||
{<<"item">>, <<"jabber:iq:search">>} ->
|
||||
@ -40,6 +58,9 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) ->
|
||||
IgnoreEls, _el);
|
||||
{<<"store">>, <<"urn:xmpp:hints">>} ->
|
||||
decode_hint_store(<<"urn:xmpp:hints">>, IgnoreEls, _el);
|
||||
{<<"no-storage">>, <<"urn:xmpp:hints">>} ->
|
||||
decode_hint_no_storage(<<"urn:xmpp:hints">>, IgnoreEls,
|
||||
_el);
|
||||
{<<"no-store">>, <<"urn:xmpp:hints">>} ->
|
||||
decode_hint_no_store(<<"urn:xmpp:hints">>, IgnoreEls,
|
||||
_el);
|
||||
@ -1162,6 +1183,13 @@ decode({xmlel, _name, _attrs, _} = _el, Opts) ->
|
||||
|
||||
is_known_tag({xmlel, _name, _attrs, _} = _el) ->
|
||||
case {_name, get_attr(<<"xmlns">>, _attrs)} of
|
||||
{<<"x">>, <<"jabber:x:expire">>} -> true;
|
||||
{<<"x">>, <<"jabber:x:event">>} -> true;
|
||||
{<<"id">>, <<"jabber:x:event">>} -> true;
|
||||
{<<"composing">>, <<"jabber:x:event">>} -> true;
|
||||
{<<"displayed">>, <<"jabber:x:event">>} -> true;
|
||||
{<<"delivered">>, <<"jabber:x:event">>} -> true;
|
||||
{<<"offline">>, <<"jabber:x:event">>} -> true;
|
||||
{<<"query">>, <<"jabber:iq:search">>} -> true;
|
||||
{<<"item">>, <<"jabber:iq:search">>} -> true;
|
||||
{<<"email">>, <<"jabber:iq:search">>} -> true;
|
||||
@ -1172,6 +1200,7 @@ is_known_tag({xmlel, _name, _attrs, _} = _el) ->
|
||||
{<<"no-permanent-store">>, <<"urn:xmpp:hints">>} ->
|
||||
true;
|
||||
{<<"store">>, <<"urn:xmpp:hints">>} -> true;
|
||||
{<<"no-storage">>, <<"urn:xmpp:hints">>} -> true;
|
||||
{<<"no-store">>, <<"urn:xmpp:hints">>} -> true;
|
||||
{<<"no-copy">>, <<"urn:xmpp:hints">>} -> true;
|
||||
{<<"participant">>, <<"urn:xmpp:mix:0">>} -> true;
|
||||
@ -2289,6 +2318,9 @@ encode({hint, 'no-copy'} = No_copy) ->
|
||||
encode({hint, 'no-store'} = No_store) ->
|
||||
encode_hint_no_store(No_store,
|
||||
[{<<"xmlns">>, <<"urn:xmpp:hints">>}]);
|
||||
encode({hint, 'no-storage'} = No_storage) ->
|
||||
encode_hint_no_storage(No_storage,
|
||||
[{<<"xmlns">>, <<"urn:xmpp:hints">>}]);
|
||||
encode({hint, store} = Store) ->
|
||||
encode_hint_store(Store,
|
||||
[{<<"xmlns">>, <<"urn:xmpp:hints">>}]);
|
||||
@ -2301,7 +2333,12 @@ encode({search_item, _, _, _, _, _} = Item) ->
|
||||
[{<<"xmlns">>, <<"jabber:iq:search">>}]);
|
||||
encode({search, _, _, _, _, _, _, _} = Query) ->
|
||||
encode_search(Query,
|
||||
[{<<"xmlns">>, <<"jabber:iq:search">>}]).
|
||||
[{<<"xmlns">>, <<"jabber:iq:search">>}]);
|
||||
encode({xevent, _, _, _, _, _} = X) ->
|
||||
encode_xevent(X, [{<<"xmlns">>, <<"jabber:x:event">>}]);
|
||||
encode({expire, _, _} = X) ->
|
||||
encode_expire(X,
|
||||
[{<<"xmlns">>, <<"jabber:x:expire">>}]).
|
||||
|
||||
get_name({last, _, _}) -> <<"query">>;
|
||||
get_name({version, _, _, _}) -> <<"query">>;
|
||||
@ -2460,11 +2497,14 @@ get_name({mix_leave}) -> <<"leave">>;
|
||||
get_name({mix_participant, _, _}) -> <<"participant">>;
|
||||
get_name({hint, 'no-copy'}) -> <<"no-copy">>;
|
||||
get_name({hint, 'no-store'}) -> <<"no-store">>;
|
||||
get_name({hint, 'no-storage'}) -> <<"no-storage">>;
|
||||
get_name({hint, store}) -> <<"store">>;
|
||||
get_name({hint, 'no-permanent-store'}) ->
|
||||
<<"no-permanent-store">>;
|
||||
get_name({search_item, _, _, _, _, _}) -> <<"item">>;
|
||||
get_name({search, _, _, _, _, _, _, _}) -> <<"query">>.
|
||||
get_name({search, _, _, _, _, _, _, _}) -> <<"query">>;
|
||||
get_name({xevent, _, _, _, _, _}) -> <<"x">>;
|
||||
get_name({expire, _, _}) -> <<"x">>.
|
||||
|
||||
get_ns({last, _, _}) -> <<"jabber:iq:last">>;
|
||||
get_ns({version, _, _, _}) -> <<"jabber:iq:version">>;
|
||||
@ -2685,13 +2725,16 @@ get_ns({mix_leave}) -> <<"urn:xmpp:mix:0">>;
|
||||
get_ns({mix_participant, _, _}) -> <<"urn:xmpp:mix:0">>;
|
||||
get_ns({hint, 'no-copy'}) -> <<"urn:xmpp:hints">>;
|
||||
get_ns({hint, 'no-store'}) -> <<"urn:xmpp:hints">>;
|
||||
get_ns({hint, 'no-storage'}) -> <<"urn:xmpp:hints">>;
|
||||
get_ns({hint, store}) -> <<"urn:xmpp:hints">>;
|
||||
get_ns({hint, 'no-permanent-store'}) ->
|
||||
<<"urn:xmpp:hints">>;
|
||||
get_ns({search_item, _, _, _, _, _}) ->
|
||||
<<"jabber:iq:search">>;
|
||||
get_ns({search, _, _, _, _, _, _, _}) ->
|
||||
<<"jabber:iq:search">>.
|
||||
<<"jabber:iq:search">>;
|
||||
get_ns({xevent, _, _, _, _, _}) -> <<"jabber:x:event">>;
|
||||
get_ns({expire, _, _}) -> <<"jabber:x:expire">>.
|
||||
|
||||
dec_int(Val) -> dec_int(Val, infinity, infinity).
|
||||
|
||||
@ -2908,6 +2951,9 @@ pp(hint, 1) -> [type];
|
||||
pp(search_item, 5) -> [jid, first, last, nick, email];
|
||||
pp(search, 7) ->
|
||||
[instructions, first, last, nick, email, items, xdata];
|
||||
pp(xevent, 5) ->
|
||||
[offline, delivered, displayed, composing, id];
|
||||
pp(expire, 2) -> [seconds, stored];
|
||||
pp(_, _) -> no.
|
||||
|
||||
join([], _Sep) -> <<>>;
|
||||
@ -2954,6 +3000,267 @@ dec_tzo(Val) ->
|
||||
M = jlib:binary_to_integer(M1),
|
||||
if H >= -12, H =< 12, M >= 0, M < 60 -> {H, M} end.
|
||||
|
||||
decode_expire(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"x">>, _attrs, _els}) ->
|
||||
{Seconds, Stored} = decode_expire_attrs(__TopXMLNS,
|
||||
_attrs, undefined, undefined),
|
||||
{expire, Seconds, Stored}.
|
||||
|
||||
decode_expire_attrs(__TopXMLNS,
|
||||
[{<<"seconds">>, _val} | _attrs], _Seconds, Stored) ->
|
||||
decode_expire_attrs(__TopXMLNS, _attrs, _val, Stored);
|
||||
decode_expire_attrs(__TopXMLNS,
|
||||
[{<<"stored">>, _val} | _attrs], Seconds, _Stored) ->
|
||||
decode_expire_attrs(__TopXMLNS, _attrs, Seconds, _val);
|
||||
decode_expire_attrs(__TopXMLNS, [_ | _attrs], Seconds,
|
||||
Stored) ->
|
||||
decode_expire_attrs(__TopXMLNS, _attrs, Seconds,
|
||||
Stored);
|
||||
decode_expire_attrs(__TopXMLNS, [], Seconds, Stored) ->
|
||||
{decode_expire_attr_seconds(__TopXMLNS, Seconds),
|
||||
decode_expire_attr_stored(__TopXMLNS, Stored)}.
|
||||
|
||||
encode_expire({expire, Seconds, Stored},
|
||||
_xmlns_attrs) ->
|
||||
_els = [],
|
||||
_attrs = encode_expire_attr_stored(Stored,
|
||||
encode_expire_attr_seconds(Seconds,
|
||||
_xmlns_attrs)),
|
||||
{xmlel, <<"x">>, _attrs, _els}.
|
||||
|
||||
decode_expire_attr_seconds(__TopXMLNS, undefined) ->
|
||||
erlang:error({xmpp_codec,
|
||||
{missing_attr, <<"seconds">>, <<"x">>, __TopXMLNS}});
|
||||
decode_expire_attr_seconds(__TopXMLNS, _val) ->
|
||||
case catch dec_int(_val, 0, infinity) of
|
||||
{'EXIT', _} ->
|
||||
erlang:error({xmpp_codec,
|
||||
{bad_attr_value, <<"seconds">>, <<"x">>, __TopXMLNS}});
|
||||
_res -> _res
|
||||
end.
|
||||
|
||||
encode_expire_attr_seconds(_val, _acc) ->
|
||||
[{<<"seconds">>, enc_int(_val)} | _acc].
|
||||
|
||||
decode_expire_attr_stored(__TopXMLNS, undefined) ->
|
||||
undefined;
|
||||
decode_expire_attr_stored(__TopXMLNS, _val) ->
|
||||
case catch dec_int(_val, 0, infinity) of
|
||||
{'EXIT', _} ->
|
||||
erlang:error({xmpp_codec,
|
||||
{bad_attr_value, <<"stored">>, <<"x">>, __TopXMLNS}});
|
||||
_res -> _res
|
||||
end.
|
||||
|
||||
encode_expire_attr_stored(undefined, _acc) -> _acc;
|
||||
encode_expire_attr_stored(_val, _acc) ->
|
||||
[{<<"stored">>, enc_int(_val)} | _acc].
|
||||
|
||||
decode_xevent(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"x">>, _attrs, _els}) ->
|
||||
{Id, Displayed, Delivered, Offline, Composing} =
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els,
|
||||
undefined, false, false, false, false),
|
||||
{xevent, Offline, Delivered, Displayed, Composing, Id}.
|
||||
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, [], Id,
|
||||
Displayed, Delivered, Offline, Composing) ->
|
||||
{Id, Displayed, Delivered, Offline, Composing};
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls,
|
||||
[{xmlel, <<"offline">>, _attrs, _} = _el | _els], Id,
|
||||
Displayed, Delivered, Offline, Composing) ->
|
||||
case get_attr(<<"xmlns">>, _attrs) of
|
||||
<<"">> when __TopXMLNS == <<"jabber:x:event">> ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id,
|
||||
Displayed, Delivered,
|
||||
decode_xevent_offline(__TopXMLNS, __IgnoreEls, _el),
|
||||
Composing);
|
||||
<<"jabber:x:event">> ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id,
|
||||
Displayed, Delivered,
|
||||
decode_xevent_offline(<<"jabber:x:event">>,
|
||||
__IgnoreEls, _el),
|
||||
Composing);
|
||||
_ ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id,
|
||||
Displayed, Delivered, Offline, Composing)
|
||||
end;
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls,
|
||||
[{xmlel, <<"delivered">>, _attrs, _} = _el | _els], Id,
|
||||
Displayed, Delivered, Offline, Composing) ->
|
||||
case get_attr(<<"xmlns">>, _attrs) of
|
||||
<<"">> when __TopXMLNS == <<"jabber:x:event">> ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id,
|
||||
Displayed,
|
||||
decode_xevent_delivered(__TopXMLNS, __IgnoreEls,
|
||||
_el),
|
||||
Offline, Composing);
|
||||
<<"jabber:x:event">> ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id,
|
||||
Displayed,
|
||||
decode_xevent_delivered(<<"jabber:x:event">>,
|
||||
__IgnoreEls, _el),
|
||||
Offline, Composing);
|
||||
_ ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id,
|
||||
Displayed, Delivered, Offline, Composing)
|
||||
end;
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls,
|
||||
[{xmlel, <<"displayed">>, _attrs, _} = _el | _els], Id,
|
||||
Displayed, Delivered, Offline, Composing) ->
|
||||
case get_attr(<<"xmlns">>, _attrs) of
|
||||
<<"">> when __TopXMLNS == <<"jabber:x:event">> ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id,
|
||||
decode_xevent_displayed(__TopXMLNS, __IgnoreEls,
|
||||
_el),
|
||||
Delivered, Offline, Composing);
|
||||
<<"jabber:x:event">> ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id,
|
||||
decode_xevent_displayed(<<"jabber:x:event">>,
|
||||
__IgnoreEls, _el),
|
||||
Delivered, Offline, Composing);
|
||||
_ ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id,
|
||||
Displayed, Delivered, Offline, Composing)
|
||||
end;
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls,
|
||||
[{xmlel, <<"composing">>, _attrs, _} = _el | _els], Id,
|
||||
Displayed, Delivered, Offline, Composing) ->
|
||||
case get_attr(<<"xmlns">>, _attrs) of
|
||||
<<"">> when __TopXMLNS == <<"jabber:x:event">> ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id,
|
||||
Displayed, Delivered, Offline,
|
||||
decode_xevent_composing(__TopXMLNS, __IgnoreEls,
|
||||
_el));
|
||||
<<"jabber:x:event">> ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id,
|
||||
Displayed, Delivered, Offline,
|
||||
decode_xevent_composing(<<"jabber:x:event">>,
|
||||
__IgnoreEls, _el));
|
||||
_ ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id,
|
||||
Displayed, Delivered, Offline, Composing)
|
||||
end;
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls,
|
||||
[{xmlel, <<"id">>, _attrs, _} = _el | _els], Id,
|
||||
Displayed, Delivered, Offline, Composing) ->
|
||||
case get_attr(<<"xmlns">>, _attrs) of
|
||||
<<"">> when __TopXMLNS == <<"jabber:x:event">> ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els,
|
||||
decode_xevent_id(__TopXMLNS, __IgnoreEls, _el),
|
||||
Displayed, Delivered, Offline, Composing);
|
||||
<<"jabber:x:event">> ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els,
|
||||
decode_xevent_id(<<"jabber:x:event">>, __IgnoreEls,
|
||||
_el),
|
||||
Displayed, Delivered, Offline, Composing);
|
||||
_ ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id,
|
||||
Displayed, Delivered, Offline, Composing)
|
||||
end;
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, [_ | _els],
|
||||
Id, Displayed, Delivered, Offline, Composing) ->
|
||||
decode_xevent_els(__TopXMLNS, __IgnoreEls, _els, Id,
|
||||
Displayed, Delivered, Offline, Composing).
|
||||
|
||||
encode_xevent({xevent, Offline, Delivered, Displayed,
|
||||
Composing, Id},
|
||||
_xmlns_attrs) ->
|
||||
_els = lists:reverse('encode_xevent_$id'(Id,
|
||||
'encode_xevent_$displayed'(Displayed,
|
||||
'encode_xevent_$delivered'(Delivered,
|
||||
'encode_xevent_$offline'(Offline,
|
||||
'encode_xevent_$composing'(Composing,
|
||||
[])))))),
|
||||
_attrs = _xmlns_attrs,
|
||||
{xmlel, <<"x">>, _attrs, _els}.
|
||||
|
||||
'encode_xevent_$id'(undefined, _acc) -> _acc;
|
||||
'encode_xevent_$id'(Id, _acc) ->
|
||||
[encode_xevent_id(Id, []) | _acc].
|
||||
|
||||
'encode_xevent_$displayed'(false, _acc) -> _acc;
|
||||
'encode_xevent_$displayed'(Displayed, _acc) ->
|
||||
[encode_xevent_displayed(Displayed, []) | _acc].
|
||||
|
||||
'encode_xevent_$delivered'(false, _acc) -> _acc;
|
||||
'encode_xevent_$delivered'(Delivered, _acc) ->
|
||||
[encode_xevent_delivered(Delivered, []) | _acc].
|
||||
|
||||
'encode_xevent_$offline'(false, _acc) -> _acc;
|
||||
'encode_xevent_$offline'(Offline, _acc) ->
|
||||
[encode_xevent_offline(Offline, []) | _acc].
|
||||
|
||||
'encode_xevent_$composing'(false, _acc) -> _acc;
|
||||
'encode_xevent_$composing'(Composing, _acc) ->
|
||||
[encode_xevent_composing(Composing, []) | _acc].
|
||||
|
||||
decode_xevent_id(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"id">>, _attrs, _els}) ->
|
||||
Cdata = decode_xevent_id_els(__TopXMLNS, __IgnoreEls,
|
||||
_els, <<>>),
|
||||
Cdata.
|
||||
|
||||
decode_xevent_id_els(__TopXMLNS, __IgnoreEls, [],
|
||||
Cdata) ->
|
||||
decode_xevent_id_cdata(__TopXMLNS, Cdata);
|
||||
decode_xevent_id_els(__TopXMLNS, __IgnoreEls,
|
||||
[{xmlcdata, _data} | _els], Cdata) ->
|
||||
decode_xevent_id_els(__TopXMLNS, __IgnoreEls, _els,
|
||||
<<Cdata/binary, _data/binary>>);
|
||||
decode_xevent_id_els(__TopXMLNS, __IgnoreEls,
|
||||
[_ | _els], Cdata) ->
|
||||
decode_xevent_id_els(__TopXMLNS, __IgnoreEls, _els,
|
||||
Cdata).
|
||||
|
||||
encode_xevent_id(Cdata, _xmlns_attrs) ->
|
||||
_els = encode_xevent_id_cdata(Cdata, []),
|
||||
_attrs = _xmlns_attrs,
|
||||
{xmlel, <<"id">>, _attrs, _els}.
|
||||
|
||||
decode_xevent_id_cdata(__TopXMLNS, <<>>) -> undefined;
|
||||
decode_xevent_id_cdata(__TopXMLNS, _val) -> _val.
|
||||
|
||||
encode_xevent_id_cdata(undefined, _acc) -> _acc;
|
||||
encode_xevent_id_cdata(_val, _acc) ->
|
||||
[{xmlcdata, _val} | _acc].
|
||||
|
||||
decode_xevent_composing(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"composing">>, _attrs, _els}) ->
|
||||
true.
|
||||
|
||||
encode_xevent_composing(true, _xmlns_attrs) ->
|
||||
_els = [],
|
||||
_attrs = _xmlns_attrs,
|
||||
{xmlel, <<"composing">>, _attrs, _els}.
|
||||
|
||||
decode_xevent_displayed(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"displayed">>, _attrs, _els}) ->
|
||||
true.
|
||||
|
||||
encode_xevent_displayed(true, _xmlns_attrs) ->
|
||||
_els = [],
|
||||
_attrs = _xmlns_attrs,
|
||||
{xmlel, <<"displayed">>, _attrs, _els}.
|
||||
|
||||
decode_xevent_delivered(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"delivered">>, _attrs, _els}) ->
|
||||
true.
|
||||
|
||||
encode_xevent_delivered(true, _xmlns_attrs) ->
|
||||
_els = [],
|
||||
_attrs = _xmlns_attrs,
|
||||
{xmlel, <<"delivered">>, _attrs, _els}.
|
||||
|
||||
decode_xevent_offline(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"offline">>, _attrs, _els}) ->
|
||||
true.
|
||||
|
||||
encode_xevent_offline(true, _xmlns_attrs) ->
|
||||
_els = [],
|
||||
_attrs = _xmlns_attrs,
|
||||
{xmlel, <<"offline">>, _attrs, _els}.
|
||||
|
||||
decode_search(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"query">>, _attrs, _els}) ->
|
||||
{Xdata, Items, Instructions, Last, First, Nick, Email} =
|
||||
@ -3459,6 +3766,16 @@ encode_hint_store({hint, store}, _xmlns_attrs) ->
|
||||
_attrs = _xmlns_attrs,
|
||||
{xmlel, <<"store">>, _attrs, _els}.
|
||||
|
||||
decode_hint_no_storage(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"no-storage">>, _attrs, _els}) ->
|
||||
{hint, 'no-storage'}.
|
||||
|
||||
encode_hint_no_storage({hint, 'no-storage'},
|
||||
_xmlns_attrs) ->
|
||||
_els = [],
|
||||
_attrs = _xmlns_attrs,
|
||||
{xmlel, <<"no-storage">>, _attrs, _els}.
|
||||
|
||||
decode_hint_no_store(__TopXMLNS, __IgnoreEls,
|
||||
{xmlel, <<"no-store">>, _attrs, _els}) ->
|
||||
{hint, 'no-store'}.
|
||||
|
@ -2536,7 +2536,8 @@
|
||||
#attr{name = <<"nick">>,
|
||||
label = '$nick'}]}).
|
||||
|
||||
-record(hint, {type :: 'no-copy' | 'no-store' | 'store' | 'no-permanent-store'}).
|
||||
-record(hint, {type :: 'no-copy' | 'no-store' | 'no-storage' |
|
||||
'store' | 'no-permanent-store'}).
|
||||
-type hint() :: #hint{}.
|
||||
|
||||
-xml(hint_no_copy,
|
||||
@ -2549,6 +2550,11 @@
|
||||
xmlns = <<"urn:xmpp:hints">>,
|
||||
result = {hint, 'no-store'}}).
|
||||
|
||||
-xml(hint_no_storage,
|
||||
#elem{name = <<"no-storage">>,
|
||||
xmlns = <<"urn:xmpp:hints">>,
|
||||
result = {hint, 'no-storage'}}).
|
||||
|
||||
-xml(hint_store,
|
||||
#elem{name = <<"store">>,
|
||||
xmlns = <<"urn:xmpp:hints">>,
|
||||
@ -2621,6 +2627,56 @@
|
||||
#ref{name = xdata, min = 0, max = 1,
|
||||
label = '$xdata'}]}).
|
||||
|
||||
-xml(xevent_offline,
|
||||
#elem{name = <<"offline">>,
|
||||
xmlns = <<"jabber:x:event">>,
|
||||
result = true}).
|
||||
-xml(xevent_delivered,
|
||||
#elem{name = <<"delivered">>,
|
||||
xmlns = <<"jabber:x:event">>,
|
||||
result = true}).
|
||||
-xml(xevent_displayed,
|
||||
#elem{name = <<"displayed">>,
|
||||
xmlns = <<"jabber:x:event">>,
|
||||
result = true}).
|
||||
-xml(xevent_composing,
|
||||
#elem{name = <<"composing">>,
|
||||
xmlns = <<"jabber:x:event">>,
|
||||
result = true}).
|
||||
-xml(xevent_id,
|
||||
#elem{name = <<"id">>,
|
||||
xmlns = <<"jabber:x:event">>,
|
||||
cdata = #cdata{},
|
||||
result = '$cdata'}).
|
||||
|
||||
-xml(xevent,
|
||||
#elem{name = <<"x">>,
|
||||
xmlns = <<"jabber:x:event">>,
|
||||
result = {xevent, '$offline', '$delivered', '$displayed',
|
||||
'$composing', '$id'},
|
||||
refs = [#ref{name = xevent_offline, min = 0, max = 1,
|
||||
label = '$offline', default = false},
|
||||
#ref{name = xevent_delivered, min = 0, max = 1,
|
||||
label = '$delivered', default = false},
|
||||
#ref{name = xevent_displayed, min = 0, max = 1,
|
||||
label = '$displayed', default = false},
|
||||
#ref{name = xevent_composing, min = 0, max = 1,
|
||||
label = '$composing', default = false},
|
||||
#ref{name = xevent_id, min = 0, max = 1,
|
||||
label = '$id'}]}).
|
||||
|
||||
-xml(expire,
|
||||
#elem{name = <<"x">>,
|
||||
xmlns = <<"jabber:x:expire">>,
|
||||
result = {expire, '$seconds', '$stored'},
|
||||
attrs = [#attr{name = <<"seconds">>,
|
||||
required = true,
|
||||
dec = {dec_int, [0, infinity]},
|
||||
enc = {enc_int, []}},
|
||||
#attr{name = <<"stored">>,
|
||||
dec = {dec_int, [0, infinity]},
|
||||
enc = {enc_int, []}}]}).
|
||||
|
||||
dec_tzo(Val) ->
|
||||
[H1, M1] = str:tokens(Val, <<":">>),
|
||||
H = jlib:binary_to_integer(H1),
|
||||
|
Loading…
Reference in New Issue
Block a user