mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
* src/jlib.erl: Implementation of XEP-0059 Result Set
Management (thanks to Eric Cestari)(EJAB-807) * src/jlib.hrl: Likewise * src/mod_muc/mod_muc.erl: Likewise SVN Revision: 1750
This commit is contained in:
parent
17cbd1614a
commit
35b1e2885e
@ -1,3 +1,10 @@
|
|||||||
|
2008-12-23 Badlop <badlop@process-one.net>
|
||||||
|
|
||||||
|
* src/jlib.erl: Implementation of XEP-0059 Result Set
|
||||||
|
Management (thanks to Eric Cestari)(EJAB-807)
|
||||||
|
* src/jlib.hrl: Likewise
|
||||||
|
* src/mod_muc/mod_muc.erl: Likewise
|
||||||
|
|
||||||
2008-12-23 Christophe Romain <christophe.romain@process-one.net>
|
2008-12-23 Christophe Romain <christophe.romain@process-one.net>
|
||||||
|
|
||||||
* src/mod_pubsub/mod_pubsub.erl: Improve handling of PEP sent to
|
* src/mod_pubsub/mod_pubsub.erl: Improve handling of PEP sent to
|
||||||
|
70
src/jlib.erl
70
src/jlib.erl
@ -62,7 +62,10 @@
|
|||||||
datetime_string_to_timestamp/1,
|
datetime_string_to_timestamp/1,
|
||||||
decode_base64/1,
|
decode_base64/1,
|
||||||
encode_base64/1,
|
encode_base64/1,
|
||||||
ip_to_list/1]).
|
ip_to_list/1,
|
||||||
|
rsm_encode/1,
|
||||||
|
rsm_encode/2,
|
||||||
|
rsm_decode/1]).
|
||||||
|
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
|
|
||||||
@ -484,6 +487,71 @@ parse_xdata_values([{xmlelement, Name, _Attrs, SubEls} | Els], Res) ->
|
|||||||
parse_xdata_values([_ | Els], Res) ->
|
parse_xdata_values([_ | Els], Res) ->
|
||||||
parse_xdata_values(Els, Res).
|
parse_xdata_values(Els, Res).
|
||||||
|
|
||||||
|
rsm_decode(#iq{sub_el=SubEl})->
|
||||||
|
rsm_decode(SubEl);
|
||||||
|
rsm_decode({xmlelement, _,_,_}=SubEl)->
|
||||||
|
case xml:get_subtag(SubEl,"set") of
|
||||||
|
false ->
|
||||||
|
none;
|
||||||
|
{xmlelement, "set", _Attrs, SubEls}->
|
||||||
|
lists:foldl(fun rsm_parse_element/2, #rsm_in{}, SubEls)
|
||||||
|
end.
|
||||||
|
|
||||||
|
rsm_parse_element({xmlelement, "max",[], _}=Elem, RsmIn)->
|
||||||
|
CountStr = xml:get_tag_cdata(Elem),
|
||||||
|
{Count, _} = string:to_integer(CountStr),
|
||||||
|
RsmIn#rsm_in{max=Count};
|
||||||
|
|
||||||
|
rsm_parse_element({xmlelement, "before", [], _}=Elem, RsmIn)->
|
||||||
|
UID = xml:get_tag_cdata(Elem),
|
||||||
|
RsmIn#rsm_in{direction=before, id=UID};
|
||||||
|
|
||||||
|
rsm_parse_element({xmlelement, "after", [], _}=Elem, RsmIn)->
|
||||||
|
UID = xml:get_tag_cdata(Elem),
|
||||||
|
RsmIn#rsm_in{direction=aft, id=UID};
|
||||||
|
|
||||||
|
rsm_parse_element({xmlelement, "index",[], _}=Elem, RsmIn)->
|
||||||
|
IndexStr = xml:get_tag_cdata(Elem),
|
||||||
|
{Index, _} = string:to_integer(IndexStr),
|
||||||
|
RsmIn#rsm_in{index=Index};
|
||||||
|
|
||||||
|
|
||||||
|
rsm_parse_element(_, RsmIn)->
|
||||||
|
RsmIn.
|
||||||
|
|
||||||
|
rsm_encode(#iq{sub_el=SubEl}=IQ,RsmOut)->
|
||||||
|
Set = {xmlelement, "set", [{"xmlns", ?NS_RSM}],
|
||||||
|
lists:reverse(rsm_encode_out(RsmOut))},
|
||||||
|
{xmlelement, Name, Attrs, SubEls} = SubEl,
|
||||||
|
New = {xmlelement, Name, Attrs, [Set | SubEls]},
|
||||||
|
IQ#iq{sub_el=New}.
|
||||||
|
|
||||||
|
rsm_encode(none)->
|
||||||
|
[];
|
||||||
|
rsm_encode(RsmOut)->
|
||||||
|
[{xmlelement, "set", [{"xmlns", ?NS_RSM}], lists:reverse(rsm_encode_out(RsmOut))}].
|
||||||
|
rsm_encode_out(#rsm_out{count=Count, index=Index, first=First, last=Last})->
|
||||||
|
El = rsm_encode_first(First, Index, []),
|
||||||
|
El2 = rsm_encode_last(Last,El),
|
||||||
|
rsm_encode_count(Count, El2).
|
||||||
|
|
||||||
|
rsm_encode_first(undefined, undefined, Arr) ->
|
||||||
|
Arr;
|
||||||
|
rsm_encode_first(First, undefined, Arr) ->
|
||||||
|
[{xmlelement, "first",[], [{xmlcdata, First}]}|Arr];
|
||||||
|
rsm_encode_first(First, Index, Arr) ->
|
||||||
|
[{xmlelement, "first",[{"index", i2l(Index)}], [{xmlcdata, First}]}|Arr].
|
||||||
|
|
||||||
|
rsm_encode_last(undefined, Arr) -> Arr;
|
||||||
|
rsm_encode_last(Last, Arr) ->
|
||||||
|
[{xmlelement, "last",[], [{xmlcdata, Last}]}|Arr].
|
||||||
|
|
||||||
|
rsm_encode_count(undefined, Arr)-> Arr;
|
||||||
|
rsm_encode_count(Count, Arr)->
|
||||||
|
[{xmlelement, "count",[], [{xmlcdata, i2l(Count)}]} | Arr].
|
||||||
|
|
||||||
|
i2l(I) when is_integer(I) -> integer_to_list(I);
|
||||||
|
i2l(L) when is_list(L) -> L.
|
||||||
|
|
||||||
timestamp_to_iso({{Year, Month, Day}, {Hour, Minute, Second}}) ->
|
timestamp_to_iso({{Year, Month, Day}, {Hour, Minute, Second}}) ->
|
||||||
lists:flatten(
|
lists:flatten(
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
-define(NS_BYTESTREAMS, "http://jabber.org/protocol/bytestreams").
|
-define(NS_BYTESTREAMS, "http://jabber.org/protocol/bytestreams").
|
||||||
-define(NS_ADMIN, "http://jabber.org/protocol/admin").
|
-define(NS_ADMIN, "http://jabber.org/protocol/admin").
|
||||||
|
|
||||||
|
-define(NS_RSM, "http://jabber.org/protocol/rsm").
|
||||||
-define(NS_EJABBERD_CONFIG, "ejabberd:config").
|
-define(NS_EJABBERD_CONFIG, "ejabberd:config").
|
||||||
|
|
||||||
-define(NS_STREAM, "http://etherx.jabber.org/streams").
|
-define(NS_STREAM, "http://etherx.jabber.org/streams").
|
||||||
@ -306,3 +307,5 @@
|
|||||||
lang = "",
|
lang = "",
|
||||||
sub_el}).
|
sub_el}).
|
||||||
|
|
||||||
|
-record(rsm_in, {max, direction, id, index}).
|
||||||
|
-record(rsm_out, {count, index, first, last}).
|
||||||
|
@ -124,10 +124,11 @@ forget_room(Host, Name) ->
|
|||||||
mnesia:transaction(F).
|
mnesia:transaction(F).
|
||||||
|
|
||||||
process_iq_disco_items(Host, From, To, #iq{lang = Lang} = IQ) ->
|
process_iq_disco_items(Host, From, To, #iq{lang = Lang} = IQ) ->
|
||||||
|
Rsm = jlib:rsm_decode(IQ),
|
||||||
Res = IQ#iq{type = result,
|
Res = IQ#iq{type = result,
|
||||||
sub_el = [{xmlelement, "query",
|
sub_el = [{xmlelement, "query",
|
||||||
[{"xmlns", ?NS_DISCO_ITEMS}],
|
[{"xmlns", ?NS_DISCO_ITEMS}],
|
||||||
iq_disco_items(Host, From, Lang)}]},
|
iq_disco_items(Host, From, Lang, Rsm)}]},
|
||||||
ejabberd_router:route(To,
|
ejabberd_router:route(To,
|
||||||
From,
|
From,
|
||||||
jlib:iq_to_xml(Res)).
|
jlib:iq_to_xml(Res)).
|
||||||
@ -512,10 +513,11 @@ iq_disco_info(Lang) ->
|
|||||||
{xmlelement, "feature", [{"var", ?NS_DISCO_ITEMS}], []},
|
{xmlelement, "feature", [{"var", ?NS_DISCO_ITEMS}], []},
|
||||||
{xmlelement, "feature", [{"var", ?NS_MUC}], []},
|
{xmlelement, "feature", [{"var", ?NS_MUC}], []},
|
||||||
{xmlelement, "feature", [{"var", ?NS_REGISTER}], []},
|
{xmlelement, "feature", [{"var", ?NS_REGISTER}], []},
|
||||||
|
{xmlelement, "feature", [{"var", ?NS_RSM}], []},
|
||||||
{xmlelement, "feature", [{"var", ?NS_VCARD}], []}].
|
{xmlelement, "feature", [{"var", ?NS_VCARD}], []}].
|
||||||
|
|
||||||
|
|
||||||
iq_disco_items(Host, From, Lang) ->
|
iq_disco_items(Host, From, Lang, none) ->
|
||||||
lists:zf(fun(#muc_online_room{name_host = {Name, _Host}, pid = Pid}) ->
|
lists:zf(fun(#muc_online_room{name_host = {Name, _Host}, pid = Pid}) ->
|
||||||
case catch gen_fsm:sync_send_all_state_event(
|
case catch gen_fsm:sync_send_all_state_event(
|
||||||
Pid, {get_disco_item, From, Lang}, 100) of
|
Pid, {get_disco_item, From, Lang}, 100) of
|
||||||
@ -528,7 +530,72 @@ iq_disco_items(Host, From, Lang) ->
|
|||||||
_ ->
|
_ ->
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
end, get_vh_rooms(Host)).
|
end, get_vh_rooms(Host));
|
||||||
|
|
||||||
|
iq_disco_items(Host, From, Lang, Rsm) ->
|
||||||
|
{Rooms, RsmO} = get_vh_rooms(Host, Rsm),
|
||||||
|
RsmOut = jlib:rsm_encode(RsmO),
|
||||||
|
lists:zf(fun(#muc_online_room{name_host = {Name, _Host}, pid = Pid}) ->
|
||||||
|
case catch gen_fsm:sync_send_all_state_event(
|
||||||
|
Pid, {get_disco_item, From, Lang}, 100) of
|
||||||
|
{item, Desc} ->
|
||||||
|
flush(),
|
||||||
|
{true,
|
||||||
|
{xmlelement, "item",
|
||||||
|
[{"jid", jlib:jid_to_string({Name, Host, ""})},
|
||||||
|
{"name", Desc}], []}};
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end, Rooms) ++ RsmOut.
|
||||||
|
|
||||||
|
get_vh_rooms(Host, #rsm_in{max=M, direction=Direction, id=I, index=Index})->
|
||||||
|
AllRooms = lists:sort(get_vh_rooms(Host)),
|
||||||
|
Count = erlang:length(AllRooms),
|
||||||
|
Guard = case Direction of
|
||||||
|
_ when Index =/= undefined -> [{'==', {element, 2, '$1'}, Host}];
|
||||||
|
aft -> [{'==', {element, 2, '$1'}, Host}, {'>=',{element, 1, '$1'} ,I}];
|
||||||
|
before when I =/= []-> [{'==', {element, 2, '$1'}, Host}, {'=<',{element, 1, '$1'} ,I}];
|
||||||
|
_ -> [{'==', {element, 2, '$1'}, Host}]
|
||||||
|
end,
|
||||||
|
L = lists:sort(
|
||||||
|
mnesia:dirty_select(muc_online_room,
|
||||||
|
[{#muc_online_room{name_host = '$1', _ = '_'},
|
||||||
|
Guard,
|
||||||
|
['$_']}])),
|
||||||
|
L2 = if
|
||||||
|
Index == undefined andalso Direction == before ->
|
||||||
|
lists:reverse(lists:sublist(lists:reverse(L), 1, M));
|
||||||
|
Index == undefined ->
|
||||||
|
lists:sublist(L, 1, M);
|
||||||
|
Index > Count orelse Index < 0 ->
|
||||||
|
[];
|
||||||
|
true ->
|
||||||
|
lists:sublist(L, Index+1, M)
|
||||||
|
end,
|
||||||
|
if
|
||||||
|
L2 == [] ->
|
||||||
|
{L2, #rsm_out{count=Count}};
|
||||||
|
true ->
|
||||||
|
H = hd(L2),
|
||||||
|
NewIndex = get_room_pos(H, AllRooms),
|
||||||
|
T=lists:last(L2),
|
||||||
|
{F, _}=H#muc_online_room.name_host,
|
||||||
|
{Last, _}=T#muc_online_room.name_host,
|
||||||
|
{L2, #rsm_out{first=F, last=Last, count=Count, index=NewIndex}}
|
||||||
|
end.
|
||||||
|
|
||||||
|
%% @doc Return the position of desired room in the list of rooms.
|
||||||
|
%% The room must exist in the list. The count starts in 0.
|
||||||
|
%% @spec (Desired::muc_online_room(), Rooms::[muc_online_room()]) -> integer()
|
||||||
|
get_room_pos(Desired, Rooms) ->
|
||||||
|
get_room_pos(Desired, Rooms, 0).
|
||||||
|
get_room_pos(Desired, [HeadRoom | _], HeadPosition)
|
||||||
|
when (Desired#muc_online_room.name_host ==
|
||||||
|
HeadRoom#muc_online_room.name_host) ->
|
||||||
|
HeadPosition;
|
||||||
|
get_room_pos(Desired, [_ | Rooms], HeadPosition) ->
|
||||||
|
get_room_pos(Desired, Rooms, HeadPosition + 1).
|
||||||
|
|
||||||
flush() ->
|
flush() ->
|
||||||
receive
|
receive
|
||||||
|
Loading…
Reference in New Issue
Block a user