24
1
mirror of https://github.com/processone/ejabberd.git synced 2024-06-02 21:17:12 +02:00

PubSub cleanup, EJAB-827 fix, EJAB-701 partial fix

SVN Revision: 1766
This commit is contained in:
Christophe Romain 2009-01-03 00:25:40 +00:00
parent 1f57a380c8
commit e710a24860
5 changed files with 284 additions and 391 deletions

View File

@ -1,3 +1,21 @@
2009-01-03 Christophe Romain <christophe.romain@process-one.net>
* src/mod_pubsub/mod_pubsub.erl: deliver notification depending on
presence-based-delivery configuration (EJAB-827). notification code
rewrite.
* src/mod_pubsub/mod_pubsub.erl: code cleanning, minor bugfixes
* src/mod_pubsub/node_default.erl: Likewise
* src/mod_pubsub/node_pep.erl: Likewise
* src/mod_pubsub/pubsub.hrl: Likewise
* src/mod_pubsub/mod_pubsub.erl: prevent subscribing with full jid,
waiting for full jid support (EJAB-701)
* src/mod_pubsub/mod_pubsub.erl: use of delete-any feature instead of
delete-nodes for delete item use case (fix from erroneous definition
in XEP-0060)
2008-12-29 Alexey Shchepin <alexey@process-one.net> 2008-12-29 Alexey Shchepin <alexey@process-one.net>
* src/ejabberd_c2s.erl: Bugfix in "from" attribute checking * src/ejabberd_c2s.erl: Bugfix in "from" attribute checking

View File

@ -30,7 +30,7 @@
%%% %%%
%%% @reference See <a href="http://www.xmpp.org/extensions/xep-0060.html">XEP-0060: Pubsub</a> for %%% @reference See <a href="http://www.xmpp.org/extensions/xep-0060.html">XEP-0060: Pubsub</a> for
%%% the latest version of the PubSub specification. %%% the latest version of the PubSub specification.
%%% This module uses version 1.11 of the specification as a base. %%% This module uses version 1.12 of the specification as a base.
%%% Most of the specification is implemented. %%% Most of the specification is implemented.
%%% Functions concerning configuration should be rewritten. %%% Functions concerning configuration should be rewritten.
%%% Code is derivated from the original pubsub v1.7, by Alexey Shchepin <alexey@process-one.net> %%% Code is derivated from the original pubsub v1.7, by Alexey Shchepin <alexey@process-one.net>
@ -40,7 +40,7 @@
-module(mod_pubsub). -module(mod_pubsub).
-author('christophe.romain@process-one.net'). -author('christophe.romain@process-one.net').
-version('1.11-01'). -version('1.12-01').
-behaviour(gen_server). -behaviour(gen_server).
-behaviour(gen_mod). -behaviour(gen_mod).
@ -91,9 +91,7 @@
string_to_subscription/1, string_to_subscription/1,
string_to_affiliation/1, string_to_affiliation/1,
extended_error/2, extended_error/2,
extended_error/3, extended_error/3
make_stanza/3,
route_stanza/3
]). ]).
%% API and gen_server callbacks %% API and gen_server callbacks
@ -1084,14 +1082,12 @@ find_authorization_response(Packet) ->
%% Plugins = [Plugin::string()] %% Plugins = [Plugin::string()]
%% @doc Send a message to JID with the supplied Subscription %% @doc Send a message to JID with the supplied Subscription
send_authorization_approval(Host, JID, Node, Subscription) -> send_authorization_approval(Host, JID, Node, Subscription) ->
Stanza = {xmlelement, "message", Stanza = event_stanza(
[], [{xmlelement, "subscription",
[{xmlelement, "event", [{"xmlns", ?NS_PUBSUB_EVENT}], [{"node", Node},
[{xmlelement, "subscription", {"jid", jlib:jid_to_string(JID)},
[{"node", Node}, {"subscription", subscription_to_string(Subscription)}],
{"jid", jlib:jid_to_string(JID)}, []}]),
{"subscription", subscription_to_string(Subscription)}],
[]}]}]},
ejabberd_router ! {route, service_jid(Host), JID, Stanza}. ejabberd_router ! {route, service_jid(Host), JID, Stanza}.
handle_authorization_response(Host, From, To, Packet, XFields) -> handle_authorization_response(Host, From, To, Packet, XFields) ->
@ -1282,7 +1278,6 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
%% [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "result"}], %% [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "result"}],
%% [?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NMI), %% [?XFIELD("hidden", "", "FORM_TYPE", ?NS_PUBSUB_NMI),
%% ?XFIELD("jid-single", "Node Creator", "creator", jlib:jid_to_string(OwnerKey))]}]), %% ?XFIELD("jid-single", "Node Creator", "creator", jlib:jid_to_string(OwnerKey))]}]),
%% todo publish_item(Host, ServerHost, ["pubsub", "nodes"], node_to_string(Node)),
case Result of case Result of
default -> {result, Reply}; default -> {result, Reply};
_ -> {result, Result} _ -> {result, Result}
@ -1328,14 +1323,17 @@ delete_node(Host, Node, Owner) ->
{error, Error} -> {error, Error} ->
{error, Error}; {error, Error};
{result, {Result, broadcast, Removed}} -> {result, {Result, broadcast, Removed}} ->
broadcast_removed_node(Host, Removed), lists:foreach(fun(RNode) ->
%%broadcast_retract_item(Host, ["pubsub", "nodes"], node_to_string(Node)), broadcast_removed_node(Host, RNode)
end, Removed),
case Result of case Result of
default -> {result, Reply}; default -> {result, Reply};
_ -> {result, Result} _ -> {result, Result}
end; end;
{result, {Result, Removed}} -> {result, {Result, Removed}} ->
broadcast_removed_node(Host, Removed), lists:foreach(fun(RNode) ->
broadcast_removed_node(Host, RNode)
end, Removed),
case Result of case Result of
default -> {result, Reply}; default -> {result, Reply};
_ -> {result, Result} _ -> {result, Result}
@ -1543,23 +1541,17 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
{error, Reason} -> {error, Reason} ->
{error, Reason}; {error, Reason};
{result, {Result, broadcast, Removed}} -> {result, {Result, broadcast, Removed}} ->
lists:foreach(fun(OldItem) -> broadcast_retract_items(Host, Node, Removed),
broadcast_retract_item(Host, Node, OldItem)
end, Removed),
broadcast_publish_item(Host, Node, ItemId, jlib:jid_tolower(Publisher), Payload), broadcast_publish_item(Host, Node, ItemId, jlib:jid_tolower(Publisher), Payload),
case Result of case Result of
default -> {result, Reply}; default -> {result, Reply};
_ -> {result, Result} _ -> {result, Result}
end; end;
{result, default, Removed} -> {result, default, Removed} ->
lists:foreach(fun(OldItem) -> broadcast_retract_items(Host, Node, Removed),
broadcast_retract_item(Host, Node, OldItem)
end, Removed),
{result, Reply}; {result, Reply};
{result, Result, Removed} -> {result, Result, Removed} ->
lists:foreach(fun(OldItem) -> broadcast_retract_items(Host, Node, Removed),
broadcast_retract_item(Host, Node, OldItem)
end, Removed),
{result, Result}; {result, Result};
{result, default} -> {result, default} ->
{result, Reply}; {result, Reply};
@ -1590,7 +1582,7 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) ->
Action = fun(#pubsub_node{type = Type}) -> Action = fun(#pubsub_node{type = Type}) ->
Features = features(Type), Features = features(Type),
PersistentFeature = lists:member("persistent-items", Features), PersistentFeature = lists:member("persistent-items", Features),
DeleteFeature = lists:member("delete-nodes", Features), DeleteFeature = lists:member("delete-any", Features),
if if
%%-> iq_pubsub just does that matchs %%-> iq_pubsub just does that matchs
%% %% Request does not specify an item %% %% Request does not specify an item
@ -1600,7 +1592,7 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) ->
{error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "persistent-items")}; {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "persistent-items")};
not DeleteFeature -> not DeleteFeature ->
%% Service does not support item deletion %% Service does not support item deletion
{error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "delete-nodes")}; {error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "delete-any")};
true -> true ->
node_call(Type, delete_item, [Host, Node, Publisher, ItemId]) node_call(Type, delete_item, [Host, Node, Publisher, ItemId])
end end
@ -1610,7 +1602,7 @@ delete_item(Host, Node, Publisher, ItemId, ForceNotify) ->
{error, Reason} -> {error, Reason} ->
{error, Reason}; {error, Reason};
{result, {Result, broadcast}} -> {result, {Result, broadcast}} ->
broadcast_retract_item(Host, Node, ItemId, ForceNotify), broadcast_retract_items(Host, Node, [ItemId], ForceNotify),
case Result of case Result of
default -> {result, Reply}; default -> {result, Reply};
_ -> {result, Result} _ -> {result, Result}
@ -1778,12 +1770,10 @@ send_items(Host, Node, LJID, Number) ->
[First|Tail] = Items, [First|Tail] = Items,
[lists:foldl( [lists:foldl(
fun(CurItem, LastItem) -> fun(CurItem, LastItem) ->
{_, {LMS, LS, LmS}} = LastItem#pubsub_item.creation, {_, LTimeStamp} = LastItem#pubsub_item.creation,
{_, {CMS, CS, CmS}} = CurItem#pubsub_item.creation, {_, CTimeStamp} = CurItem#pubsub_item.creation,
LTimestamp = LMS * 1000000 + LS * 1000 + LmS,
CTimestamp = CMS * 1000000 + CS * 1000 + CmS,
if if
CTimestamp > LTimestamp -> CurItem; CTimeStamp > LTimeStamp -> CurItem;
true -> LastItem true -> LastItem
end end
end, First, Tail)]; end, First, Tail)];
@ -1802,10 +1792,9 @@ send_items(Host, Node, LJID, Number) ->
end, end,
{xmlelement, "item", ItemAttrs, Payload} {xmlelement, "item", ItemAttrs, Payload}
end, ToSend), end, ToSend),
Stanza = {xmlelement, "message", [], Stanza = event_stanza(
[{xmlelement, "event", [{"xmlns", ?NS_PUBSUB_EVENT}], [{xmlelement, "items", [{"node", node_to_string(Node)}],
[{xmlelement, "items", [{"node", node_to_string(Node)}], ItemsEls}]),
ItemsEls}]}]},
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(LJID), Stanza}. ejabberd_router ! {route, service_jid(Host), jlib:make_jid(LJID), Stanza}.
%% @spec (Host, JID, Plugins) -> {error, Reason} | {result, Response} %% @spec (Host, JID, Plugins) -> {error, Reason} | {result, Response}
@ -2136,10 +2125,10 @@ service_jid(Host) ->
%% Subscription = atom() %% Subscription = atom()
%% PresenceDelivery = boolean() %% PresenceDelivery = boolean()
%% @doc <p>Check if a notification must be delivered or not.</p> %% @doc <p>Check if a notification must be delivered or not.</p>
is_to_delivered(_, none, _) -> false; is_to_deliver(_, none, _) -> false;
is_to_delivered(_, pending, _) -> false; is_to_deliver(_, pending, _) -> false;
is_to_delivered(_, _, false) -> true; is_to_deliver(_, _, false) -> true;
is_to_delivered({User, Server, _}, _, true) -> is_to_deliver({User, Server, _}, _, true) ->
case mnesia:dirty_match_object({session, '_', '_', {User, Server}, '_', '_'}) of case mnesia:dirty_match_object({session, '_', '_', {User, Server}, '_', '_'}) of
[] -> false; [] -> false;
Ss -> Ss ->
@ -2157,233 +2146,172 @@ payload_xmlelements([], Count) -> Count;
payload_xmlelements([{xmlelement, _, _, _}|Tail], Count) -> payload_xmlelements(Tail, Count+1); payload_xmlelements([{xmlelement, _, _, _}|Tail], Count) -> payload_xmlelements(Tail, Count+1);
payload_xmlelements([_|Tail], Count) -> payload_xmlelements(Tail, Count). payload_xmlelements([_|Tail], Count) -> payload_xmlelements(Tail, Count).
%% @spec (Els) -> stanza()
%% Els = [xmlelement()]
%% @doc <p>Build pubsub event stanza
event_stanza(Els) ->
{xmlelement, "message", [],
[{xmlelement, "event", [{"xmlns", ?NS_PUBSUB_EVENT}], Els}]}.
%%%%%% broadcast functions %%%%%% broadcast functions
broadcast_publish_item(Host, Node, ItemId, _From, Payload) -> broadcast_publish_item(Host, Node, ItemId, _From, Payload) ->
Action = Action =
fun(#pubsub_node{options = Options, type = Type}) -> fun(#pubsub_node{options = Options, type = Type}) ->
case node_call(Type, get_states, [Host, Node]) of case node_call(Type, get_states, [Host, Node]) of
{error, _} -> {result, false}; {result, []} ->
{result, []} -> {result, false}; {result, false};
{result, States} -> {result, States} ->
PresenceDelivery = get_option(Options, presence_based_delivery), Content = case get_option(Options, deliver_payloads) of
BroadcastAll = get_option(Options, broadcast_all_resources), true -> Payload;
Content = case get_option(Options, deliver_payloads) of false -> []
true -> Payload; end,
false -> [] ItemAttrs = case ItemId of
end, "" -> [];
ItemAttrs = case ItemId of _ -> [{"id", ItemId}]
"" -> []; end,
_ -> [{"id", ItemId}] Stanza = event_stanza(
end, [{xmlelement, "items", [{"node", node_to_string(Node)}],
Stanza = make_stanza(Node, ItemAttrs, Content), [{xmlelement, "item", ItemAttrs, Content}]}]),
lists:foreach( broadcast_stanza(Host, Options, States, Stanza),
fun(#pubsub_state{stateid = {LJID, _}, broadcast_by_caps(Host, Node, Type, Stanza),
subscription = Subscription}) -> {result, true};
case is_to_delivered(LJID, Subscription, PresenceDelivery) of _ ->
true -> {result, false}
DestJIDs = case BroadcastAll of end
true -> ejabberd_sm:get_user_resources(element(1, LJID), element(2, LJID));
false -> [LJID]
end,
route_stanza(Host, DestJIDs, Stanza);
false ->
ok
end
end, States),
broadcast_by_caps(Host, Node, Type, Stanza),
{result, true}
end
end, end,
transaction(Host, Node, Action, sync_dirty). transaction(Host, Node, Action, sync_dirty).
%% ItemAttrs is a list of tuples: broadcast_retract_items(Host, Node, ItemIds) ->
%% For example: [{"id", ItemId}] broadcast_retract_items(Host, Node, ItemIds, false).
make_stanza(Node, ItemAttrs, Payload) -> broadcast_retract_items(Host, Node, ItemIds, ForceNotify) ->
{xmlelement, "message", [],
[{xmlelement, "event",
[{"xmlns", ?NS_PUBSUB_EVENT}],
[{xmlelement, "items", [{"node", node_to_string(Node)}],
[{xmlelement, "item", ItemAttrs, Payload}]}]}]}.
%% DestJIDs = [{LUser, LServer, LResource}]
route_stanza(Host, DestJIDs, Stanza) ->
lists:foreach(
fun(DestJID) ->
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(DestJID), Stanza}
end, DestJIDs).
broadcast_retract_item(Host, Node, ItemId) ->
broadcast_retract_item(Host, Node, ItemId, false).
broadcast_retract_item(Host, Node, ItemId, ForceNotify) ->
Action = Action =
fun(#pubsub_node{options = Options, type = Type}) -> fun(#pubsub_node{options = Options, type = Type}) ->
case node_call(Type, get_states, [Host, Node]) of case (get_option(Options, notify_retract) or ForceNotify) of
{error, _} -> {result, false}; true ->
{result, []} -> {result, false}; case node_call(Type, get_states, [Host, Node]) of
{result, States} -> {result, []} ->
Notify = case ForceNotify of {result, false};
true -> true; {result, States} ->
_ -> get_option(Options, notify_retract) RetractEls = lists:map(
end, fun(ItemId) ->
ItemAttrs = case ItemId of ItemAttrs = case ItemId of
"" -> []; "" -> [];
_ -> [{"id", ItemId}] _ -> [{"id", ItemId}]
end, end,
Stanza = {xmlelement, "message", [], {xmlelement, "retract", ItemAttrs, []}
[{xmlelement, "event", end, ItemIds),
[{"xmlns", ?NS_PUBSUB_EVENT}], Stanza = event_stanza(
[{xmlelement, "items", [{"node", node_to_string(Node)}], [{xmlelement, "items", [{"node", node_to_string(Node)}],
[{xmlelement, "retract", ItemAttrs, []}]}]}]}, RetractEls}]),
case Notify of broadcast_stanza(Host, Options, States, Stanza),
true -> broadcast_by_caps(Host, Node, Type, Stanza),
lists:foreach( {result, true};
fun(#pubsub_state{stateid = {JID, _}, _ ->
subscription = Subscription}) -> {result, false}
if (Subscription /= none) and end;
(Subscription /= pending) -> _ ->
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(JID), Stanza}; {result, false}
true -> end
ok
end
end, States),
broadcast_by_caps(Host, Node, Type, Stanza),
{result, true};
false ->
{result, false}
end
end
end, end,
transaction(Host, Node, Action, sync_dirty). transaction(Host, Node, Action, sync_dirty).
broadcast_purge_node(Host, Node) -> broadcast_purge_node(Host, Node) ->
Action = Action =
fun(#pubsub_node{options = Options, type = Type}) -> fun(#pubsub_node{options = Options, type = Type}) ->
case node_call(Type, get_states, [Host, Node]) of case get_option(Options, notify_retract) of
{error, _} -> {result, false}; true ->
{result, []} -> {result, false}; case node_call(Type, get_states, [Host, Node]) of
{result, States} -> {result, []} ->
Stanza = {xmlelement, "message", [], {result, false};
[{xmlelement, "event", {result, States} ->
[{"xmlns", ?NS_PUBSUB_EVENT}], Stanza = event_stanza(
[{xmlelement, "purge", [{"node", node_to_string(Node)}], [{xmlelement, "purge", [{"node", node_to_string(Node)}], []}]),
[]}]}]}, broadcast_stanza(Host, Options, States, Stanza),
case get_option(Options, notify_retract) of broadcast_by_caps(Host, Node, Type, Stanza),
true -> {result, true};
lists:foreach( _ ->
fun(#pubsub_state{stateid = {JID,_}, {result, false}
subscription = Subscription}) -> end;
if (Subscription /= none) and _ ->
(Subscription /= pending) -> {result, false}
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(JID), Stanza}; end
true ->
ok
end
end, States),
broadcast_by_caps(Host, Node, Type, Stanza),
{result, true};
false ->
{result, false}
end
end
end, end,
transaction(Host, Node, Action, sync_dirty). transaction(Host, Node, Action, sync_dirty).
broadcast_removed_node(Host, Removed) -> broadcast_removed_node(Host, Node) ->
lists:foreach( Action =
fun(Node) -> fun(#pubsub_node{options = Options, type = Type}) ->
Action = case get_option(Options, notify_delete) of
fun(#pubsub_node{options = Options, type = Type}) -> true ->
Stanza = {xmlelement, "message", [], case node_call(Type, get_states, [Host, Node]) of
[{xmlelement, "event", [{"xmlns", ?NS_PUBSUB_EVENT}], {result, []} ->
[{xmlelement, "delete", [{"node", node_to_string(Node)}], {result, false};
[]}]}]}, {result, States} ->
case get_option(Options, notify_delete) of Stanza = event_stanza(
true -> [{xmlelement, "delete", [{"node", node_to_string(Node)}], []}]),
case node_call(Type, get_states, [Host, Node]) of broadcast_stanza(Host, Options, States, Stanza),
{result, States} -> broadcast_by_caps(Host, Node, Type, Stanza),
lists:foreach( {result, true};
fun(#pubsub_state{stateid = {JID, _}, _ ->
subscription = Subscription}) -> {result, false}
if (Subscription /= none) and end;
(Subscription /= pending) -> _ ->
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(JID), Stanza}; {result, false}
true -> end
ok end,
end transaction(Host, Node, Action, sync_dirty).
end, States),
broadcast_by_caps(Host, Node, Type, Stanza),
{result, true};
_ ->
{result, false}
end;
_ ->
{result, false}
end
end,
transaction(Host, Node, Action, sync_dirty)
end, Removed).
broadcast_config_notification(Host, Node, Lang) -> broadcast_config_notification(Host, Node, Lang) ->
Action = Action =
fun(#pubsub_node{options = Options, owners = Owners, type = Type}) -> fun(#pubsub_node{options = Options, owners = Owners, type = Type}) ->
case node_call(Type, get_states, [Host, Node]) of case get_option(Options, notify_config) of
{error, _} -> {result, false}; true ->
{result, []} -> {result, false}; case node_call(Type, get_states, [Host, Node]) of
{result, States} -> {result, []} ->
case get_option(Options, notify_config) of {result, false};
true -> {result, States} ->
PresenceDelivery = get_option(Options, presence_based_delivery), Content = case get_option(Options, deliver_payloads) of
Content = case get_option(Options, deliver_payloads) of true ->
true -> [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
[{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}], get_configure_xfields(Type, Options, Lang, Owners)}];
get_configure_xfields(Type, Options, Lang, Owners)}]; false ->
false -> []
[] end,
end, Stanza = event_stanza(
Stanza = {xmlelement, "message", [], [{xmlelement, "items", [{"node", node_to_string(Node)}],
[{xmlelement, "event", [{"xmlns", ?NS_PUBSUB_EVENT}], [{xmlelement, "item", [{"id", "configuration"}],
[{xmlelement, "items", [{"node", node_to_string(Node)}], Content}]}]),
[{xmlelement, "item", [{"id", "configuration"}], broadcast_stanza(Host, Options, States, Stanza),
Content}]}]}]}, broadcast_by_caps(Host, Node, Type, Stanza),
lists:foreach( {result, true};
fun(#pubsub_state{stateid = {LJID, _}, _ ->
subscription = Subscription}) -> {result, false}
case is_to_delivered(LJID, Subscription, PresenceDelivery) of end;
true -> _ ->
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(LJID), Stanza}; {result, false}
false -> end
ok
end
end, States),
broadcast_by_caps(Host, Node, Type, Stanza),
{result, true};
_ ->
{result, false}
end
end
end, end,
transaction(Host, Node, Action, sync_dirty). transaction(Host, Node, Action, sync_dirty).
%TODO: simplify broadcast_* using a generic function like that: broadcast_stanza(Host, NodeOpts, States, Stanza) ->
%broadcast(Host, Node, Fun) -> PresenceDelivery = get_option(NodeOpts, presence_based_delivery),
% transaction(fun() -> BroadcastAll = get_option(NodeOpts, broadcast_all_resources),
% case tree_call(Host, get_node, [Host, Node]) of From = service_jid(Host),
% #pubsub_node{options = Options, owners = Owners, type = Type} -> lists:foreach(fun(#pubsub_state{stateid = {LJID, _}, subscription = Subs}) ->
% case node_call(Type, get_states, [Host, Node]) of case is_to_deliver(LJID, Subs, PresenceDelivery) of
% {error, _} -> {result, false}; true ->
% {result, []} -> {result, false}; JIDs = case BroadcastAll of
% {result, States} -> true -> ejabberd_sm:get_user_resources(element(1, LJID), element(2, LJID));
% lists:foreach(fun(#pubsub_state{stateid = {JID,_}, subscription = Subscription}) -> false -> [LJID]
% Fun(Host, Node, Options, Owners, JID, Subscription) end,
% end, States), lists:foreach(fun(JID) ->
% {result, true} ejabberd_router ! {route, From, jlib:make_jid(JID), Stanza}
% end; end, JIDs);
% Other -> false ->
% Other ok
% end end
% end, sync_dirty). end, States).
%% broadcast Stanza to all contacts of the user that are advertising %% broadcast Stanza to all contacts of the user that are advertising
%% interest in this kind of Node. %% interest in this kind of Node.
@ -2734,18 +2662,18 @@ select_type(ServerHost, Host, Node) ->
features() -> features() ->
[ [
%"access-authorize", % OPTIONAL %TODO "access-authorize", % OPTIONAL
"access-open", % OPTIONAL this relates to access_model option in node_default "access-open", % OPTIONAL this relates to access_model option in node_default
"access-presence", % OPTIONAL this relates to access_model option in node_pep "access-presence", % OPTIONAL this relates to access_model option in node_pep
%"access-roster", % OPTIONAL %TODO "access-roster", % OPTIONAL
%"access-whitelist", % OPTIONAL %TODO "access-whitelist", % OPTIONAL
% see plugin "auto-create", % OPTIONAL % see plugin "auto-create", % OPTIONAL
% see plugin "auto-subscribe", % RECOMMENDED % see plugin "auto-subscribe", % RECOMMENDED
"collections", % RECOMMENDED "collections", % RECOMMENDED
"config-node", % RECOMMENDED "config-node", % RECOMMENDED
"create-and-configure", % RECOMMENDED "create-and-configure", % RECOMMENDED
% see plugin "create-nodes", % RECOMMENDED % see plugin "create-nodes", % RECOMMENDED
%TODO "delete-any", % OPTIONAL % see plugin "delete-any", % RECOMMENDED
% see plugin "delete-nodes", % RECOMMENDED % see plugin "delete-nodes", % RECOMMENDED
% see plugin "filtered-notifications", % RECOMMENDED % see plugin "filtered-notifications", % RECOMMENDED
%TODO "get-pending", % OPTIONAL %TODO "get-pending", % OPTIONAL

View File

@ -159,6 +159,7 @@ features() ->
["create-nodes", ["create-nodes",
"auto-create", "auto-create",
"delete-nodes", "delete-nodes",
"delete-any",
"instant-nodes", "instant-nodes",
"manage-subscriptions", "manage-subscriptions",
"modify-affiliations", "modify-affiliations",
@ -220,8 +221,7 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) ->
%% @doc <p></p> %% @doc <p></p>
create_node(Host, Node, Owner) -> create_node(Host, Node, Owner) ->
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
mnesia:write(#pubsub_state{stateid = {OwnerKey, {Host, Node}}, set_state(#pubsub_state{stateid = {OwnerKey, {Host, Node}}, affiliation = owner}),
affiliation = owner, subscription = none}),
{result, {default, broadcast}}. {result, {default, broadcast}}.
@ -234,12 +234,8 @@ delete_node(Host, Removed) ->
fun(Node) -> fun(Node) ->
lists:foreach( lists:foreach(
fun(#pubsub_state{stateid = StateId, items = Items}) -> fun(#pubsub_state{stateid = StateId, items = Items}) ->
lists:foreach( del_items(Host, Node, Items),
fun(ItemId) -> del_state(StateId)
mnesia:delete(
{pubsub_item, {ItemId, {Host, Node}}})
end, Items),
mnesia:delete({pubsub_state, StateId})
end, end,
mnesia:match_object( mnesia:match_object(
#pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'})) #pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'}))
@ -281,14 +277,9 @@ delete_node(Host, Removed) ->
%% <p>In the default plugin module, the record is unchanged.</p> %% <p>In the default plugin module, the record is unchanged.</p>
subscribe_node(Host, Node, Sender, Subscriber, AccessModel, subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup) -> SendLast, PresenceSubscription, RosterGroup) ->
SenderKey = jlib:jid_tolower(Sender), SubscriberKey = jlib:jid_tolower(jlib:jid_remove_resource(Subscriber)),
Authorized = (jlib:jid_remove_resource(SenderKey) == jlib:jid_remove_resource(Subscriber)), Authorized = (jlib:jid_tolower(jlib:jid_remove_resource(Sender)) == SubscriberKey),
% TODO add some acl check for Authorized ? State = get_state(Host, Node, SubscriberKey),
State = case get_state(Host, Node, Subscriber) of
{error, ?ERR_ITEM_NOT_FOUND} ->
#pubsub_state{stateid = {Subscriber, {Host, Node}}}; % TODO: bug on Key ?
{result, S} -> S
end,
#pubsub_state{affiliation = Affiliation, #pubsub_state{affiliation = Affiliation,
subscription = Subscription} = State, subscription = Subscription} = State,
if if
@ -324,7 +315,6 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
if if
AccessModel == authorize -> AccessModel == authorize ->
pending; pending;
%%TODO Affiliation == none -> ?
%%NeedConfiguration -> %%NeedConfiguration ->
%% unconfigured %% unconfigured
true -> true ->
@ -352,43 +342,29 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
%% Reason = mod_pubsub:stanzaError() %% Reason = mod_pubsub:stanzaError()
%% @doc <p>Unsubscribe the <tt>Subscriber</tt> from the <tt>Node</tt>.</p> %% @doc <p>Unsubscribe the <tt>Subscriber</tt> from the <tt>Node</tt>.</p>
unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) -> unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) ->
SenderKey = jlib:jid_tolower(Sender), SubscriberKey = jlib:jid_tolower(jlib:jid_remove_resource(Subscriber)),
Match = jlib:jid_remove_resource(SenderKey) == jlib:jid_remove_resource(Subscriber), Authorized = (jlib:jid_tolower(jlib:jid_remove_resource(Sender)) == SubscriberKey),
Authorized = case Match of State = get_state(Host, Node, SubscriberKey),
true -> if
true; %% Entity did not specify SubID
false -> %%SubID == "", ?? ->
case get_state(Host, Node, SenderKey) of % TODO: bug on Key ? %% {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")};
{result, #pubsub_state{affiliation=owner}} -> true; %% Invalid subscription identifier
_ -> false %%InvalidSubID ->
end %% {error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
end, %% Requesting entity is not a subscriber
case get_state(Host, Node, Subscriber) of State#pubsub_state.subscription == none ->
{error, ?ERR_ITEM_NOT_FOUND} ->
%% Requesting entity is not a subscriber
{error, ?ERR_EXTENDED(?ERR_UNEXPECTED_REQUEST, "not-subscribed")}; {error, ?ERR_EXTENDED(?ERR_UNEXPECTED_REQUEST, "not-subscribed")};
{result, State} -> %% Requesting entity is prohibited from unsubscribing entity
if (not Authorized) and (State#pubsub_state.affiliation =/= owner) ->
%% Entity did not specify SubID {error, ?ERR_FORBIDDEN};
%%SubID == "", ?? -> %% Was just subscriber, remove the record
%% {error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")}; State#pubsub_state.affiliation == none ->
%% Invalid subscription identifier del_state(State#pubsub_state.stateid),
%%InvalidSubID -> {result, default};
%% {error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")}; true ->
%% Requesting entity is not a subscriber set_state(State#pubsub_state{subscription = none}),
State#pubsub_state.subscription == none -> {result, default}
{error, ?ERR_EXTENDED(?ERR_UNEXPECTED_REQUEST, "not-subscribed")};
%% Requesting entity is prohibited from unsubscribing entity
not Authorized ->
{error, ?ERR_FORBIDDEN};
%% Was just subscriber, remove the record
State#pubsub_state.affiliation == none ->
mnesia:delete({pubsub_state, State#pubsub_state.stateid}),
{result, default};
true ->
set_state(State#pubsub_state{subscription = none}),
{result, default}
end
end. end.
%% @spec (Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> %% @spec (Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
@ -432,10 +408,7 @@ unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) ->
%% <p>In the default plugin module, the record is unchanged.</p> %% <p>In the default plugin module, the record is unchanged.</p>
publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) -> publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
PublisherKey = jlib:jid_tolower(jlib:jid_remove_resource(Publisher)), PublisherKey = jlib:jid_tolower(jlib:jid_remove_resource(Publisher)),
State = case get_state(Host, Node, PublisherKey) of State = get_state(Host, Node, PublisherKey),
{error, ?ERR_ITEM_NOT_FOUND} -> #pubsub_state{stateid={PublisherKey, {Host, Node}}};
{result, S} -> S
end,
#pubsub_state{affiliation = Affiliation, #pubsub_state{affiliation = Affiliation,
subscription = Subscription} = State, subscription = Subscription} = State,
if if
@ -447,17 +420,17 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
%% Entity does not have sufficient privileges to publish to node %% Entity does not have sufficient privileges to publish to node
{error, ?ERR_FORBIDDEN}; {error, ?ERR_FORBIDDEN};
true -> true ->
PubId = {PublisherKey, now()}, PubId = {PublisherKey, now()}, %% TODO, uses {now(),PublisherKey} for sorting (EJAB-824)
%% TODO: check creation, presence, roster (EJAB-663) %% TODO: check creation, presence, roster (EJAB-663)
Item = case get_item(Host, Node, ItemId) of Item = case get_item(Host, Node, ItemId) of
{error, ?ERR_ITEM_NOT_FOUND} -> {result, OldItem} ->
OldItem#pubsub_item{modification = PubId,
payload = Payload};
_ ->
#pubsub_item{itemid = {ItemId, {Host, Node}}, #pubsub_item{itemid = {ItemId, {Host, Node}},
creation = PubId, creation = PubId,
modification = PubId, modification = PubId,
payload = Payload}; payload = Payload}
{result, OldItem} ->
OldItem#pubsub_item{modification = PubId,
payload = Payload}
end, end,
Items = [ItemId | State#pubsub_state.items--[ItemId]], Items = [ItemId | State#pubsub_state.items--[ItemId]],
{result, {NI, OI}} = remove_extra_items( {result, {NI, OI}} = remove_extra_items(
@ -491,9 +464,7 @@ remove_extra_items(Host, Node, MaxItems, ItemIds) ->
NewItems = lists:sublist(ItemIds, MaxItems), NewItems = lists:sublist(ItemIds, MaxItems),
OldItems = lists:nthtail(length(NewItems), ItemIds), OldItems = lists:nthtail(length(NewItems), ItemIds),
%% Remove extra items: %% Remove extra items:
lists:foreach(fun(ItemId) -> del_items(Host, Node, OldItems),
mnesia:delete({pubsub_item, {ItemId, {Host, Node}}})
end, OldItems),
%% Return the new items list: %% Return the new items list:
{result, {NewItems, OldItems}}. {result, {NewItems, OldItems}}.
@ -509,12 +480,7 @@ remove_extra_items(Host, Node, MaxItems, ItemIds) ->
%% or a publisher.</p> %% or a publisher.</p>
delete_item(Host, Node, Publisher, ItemId) -> delete_item(Host, Node, Publisher, ItemId) ->
PublisherKey = jlib:jid_tolower(jlib:jid_remove_resource(Publisher)), PublisherKey = jlib:jid_tolower(jlib:jid_remove_resource(Publisher)),
State = case get_state(Host, Node, PublisherKey) of State = get_state(Host, Node, PublisherKey),
{error, ?ERR_ITEM_NOT_FOUND} ->
#pubsub_state{stateid = {PublisherKey, {Host, Node}}};
{result, S} ->
S
end,
#pubsub_state{affiliation = Affiliation, items = Items} = State, #pubsub_state{affiliation = Affiliation, items = Items} = State,
Allowed = (Affiliation == publisher) orelse (Affiliation == owner) Allowed = (Affiliation == publisher) orelse (Affiliation == owner)
orelse case get_item(Host, Node, ItemId) of orelse case get_item(Host, Node, ItemId) of
@ -528,7 +494,7 @@ delete_item(Host, Node, Publisher, ItemId) ->
true -> true ->
case get_item(Host, Node, ItemId) of case get_item(Host, Node, ItemId) of
{result, _} -> {result, _} ->
mnesia:delete({pubsub_item, {ItemId, {Host, Node}}}), del_item(Host, Node, ItemId),
NewItems = lists:delete(ItemId, Items), NewItems = lists:delete(ItemId, Items),
set_state(State#pubsub_state{items = NewItems}), set_state(State#pubsub_state{items = NewItems}),
{result, {default, broadcast}}; {result, {default, broadcast}};
@ -547,16 +513,12 @@ delete_item(Host, Node, Publisher, ItemId) ->
purge_node(Host, Node, Owner) -> purge_node(Host, Node, Owner) ->
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
case get_state(Host, Node, OwnerKey) of case get_state(Host, Node, OwnerKey) of
{result, #pubsub_state{items = Items, affiliation = owner}} -> #pubsub_state{items = Items, affiliation = owner} ->
lists:foreach(fun(ItemId) -> del_items(Host, Node, Items),
mnesia:delete({pubsub_item, {ItemId, {Host, Node}}})
end, Items),
{result, {default, broadcast}}; {result, {default, broadcast}};
{result, _} ->
%% Entity is not owner
{error, ?ERR_FORBIDDEN};
_ -> _ ->
{error, ?ERR_ITEM_NOT_FOUND} %% Entity is not owner
{error, ?ERR_FORBIDDEN}
end. end.
%% @spec (Host, JID) -> [{Node,Affiliation}] %% @spec (Host, JID) -> [{Node,Affiliation}]
@ -572,8 +534,7 @@ purge_node(Host, Node, Owner) ->
get_entity_affiliations(Host, Owner) -> get_entity_affiliations(Host, Owner) ->
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
States = mnesia:match_object( States = mnesia:match_object(
#pubsub_state{stateid = {OwnerKey, {Host, '_'}}, #pubsub_state{stateid = {OwnerKey, {Host, '_'}}, _ = '_'}),
_ = '_'}),
Tr = fun(#pubsub_state{stateid = {_, {_, N}}, affiliation = A}) -> Tr = fun(#pubsub_state{stateid = {_, {_, N}}, affiliation = A}) ->
{N, A} {N, A}
end, end,
@ -581,8 +542,7 @@ get_entity_affiliations(Host, Owner) ->
get_node_affiliations(Host, Node) -> get_node_affiliations(Host, Node) ->
States = mnesia:match_object( States = mnesia:match_object(
#pubsub_state{stateid = {'_', {Host, Node}}, #pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'}),
_ = '_'}),
Tr = fun(#pubsub_state{stateid = {J, {_, _}}, affiliation = A}) -> Tr = fun(#pubsub_state{stateid = {J, {_, _}}, affiliation = A}) ->
{J, A} {J, A}
end, end,
@ -590,22 +550,13 @@ get_node_affiliations(Host, Node) ->
get_affiliation(Host, Node, Owner) -> get_affiliation(Host, Node, Owner) ->
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
Affiliation = case get_state(Host, Node, OwnerKey) of State = get_state(Host, Node, OwnerKey),
{result, #pubsub_state{affiliation = A}} -> A; {result, State#pubsub_state.affiliation}.
_ -> none
end,
{result, Affiliation}.
set_affiliation(Host, Node, Owner, Affiliation) -> set_affiliation(Host, Node, Owner, Affiliation) ->
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
Record = case get_state(Host, Node, OwnerKey) of State = get_state(Host, Node, OwnerKey),
{error, ?ERR_ITEM_NOT_FOUND} -> set_state(State#pubsub_state{affiliation = Affiliation}),
#pubsub_state{stateid = {OwnerKey, {Host, Node}},
affiliation = Affiliation};
{result, State} ->
State#pubsub_state{affiliation = Affiliation}
end,
set_state(Record),
ok. ok.
%% @spec (Host, Owner) -> [{Node,Subscription}] %% @spec (Host, Owner) -> [{Node,Subscription}]
@ -622,8 +573,7 @@ set_affiliation(Host, Node, Owner, Affiliation) ->
get_entity_subscriptions(Host, Owner) -> get_entity_subscriptions(Host, Owner) ->
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
States = mnesia:match_object( States = mnesia:match_object(
#pubsub_state{stateid = {OwnerKey, {Host, '_'}}, #pubsub_state{stateid = {OwnerKey, {Host, '_'}}, _ = '_'}),
_ = '_'}),
Tr = fun(#pubsub_state{stateid = {_, {_, N}}, subscription = S}) -> Tr = fun(#pubsub_state{stateid = {_, {_, N}}, subscription = S}) ->
{N, S} {N, S}
end, end,
@ -631,8 +581,7 @@ get_entity_subscriptions(Host, Owner) ->
get_node_subscriptions(Host, Node) -> get_node_subscriptions(Host, Node) ->
States = mnesia:match_object( States = mnesia:match_object(
#pubsub_state{stateid = {'_', {Host, Node}}, #pubsub_state{stateid = {'_', {Host, Node}}, _ = '_'}),
_ = '_'}),
Tr = fun(#pubsub_state{stateid = {J, {_, _}}, subscription = S}) -> Tr = fun(#pubsub_state{stateid = {J, {_, _}}, subscription = S}) ->
{J, S} {J, S}
end, end,
@ -640,22 +589,13 @@ get_node_subscriptions(Host, Node) ->
get_subscription(Host, Node, Owner) -> get_subscription(Host, Node, Owner) ->
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
Subscription = case get_state(Host, Node, OwnerKey) of State = get_state(Host, Node, OwnerKey),
{result, #pubsub_state{subscription = S}} -> S; {result, State#pubsub_state.subscription}.
_ -> none
end,
{result, Subscription}.
set_subscription(Host, Node, Owner, Subscription) -> set_subscription(Host, Node, Owner, Subscription) ->
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
Record = case get_state(Host, Node, OwnerKey) of State = get_state(Host, Node, OwnerKey),
{error, ?ERR_ITEM_NOT_FOUND} -> set_state(State#pubsub_state{subscription = Subscription}),
#pubsub_state{stateid = {OwnerKey, {Host, Node}},
subscription = Subscription};
{result, State} ->
State#pubsub_state{subscription = Subscription}
end,
set_state(Record),
ok. ok.
%% @spec (Host, Node) -> [States] | [] %% @spec (Host, Node) -> [States] | []
@ -684,11 +624,10 @@ get_states(Host, Node) ->
%% State = mod_pubsub:pubsubItems() %% State = mod_pubsub:pubsubItems()
%% @doc <p>Returns a state (one state list), given its reference.</p> %% @doc <p>Returns a state (one state list), given its reference.</p>
get_state(Host, Node, JID) -> get_state(Host, Node, JID) ->
case mnesia:read({pubsub_state, {JID, {Host, Node}}}) of StateId = {JID, {Host, Node}},
[State] when is_record(State, pubsub_state) -> case mnesia:read({pubsub_state, StateId}) of
{result, State}; [State] when is_record(State, pubsub_state) -> State;
_ -> _ -> #pubsub_state{stateid=StateId}
{error, ?ERR_ITEM_NOT_FOUND}
end. end.
%% @spec (State) -> ok | {error, Reason::stanzaError()} %% @spec (State) -> ok | {error, Reason::stanzaError()}
@ -699,6 +638,12 @@ set_state(State) when is_record(State, pubsub_state) ->
set_state(_) -> set_state(_) ->
{error, ?ERR_INTERNAL_SERVER_ERROR}. {error, ?ERR_INTERNAL_SERVER_ERROR}.
%% @spec (StateId) -> ok | {error, Reason::stanzaError()}
%% StateId = mod_pubsub:pubsubStateId()
%% @doc <p>Delete a state from database.</p>
del_state(StateId) ->
mnesia:delete({pubsub_state, StateId}).
%% @spec (Host, Node) -> [Items] | [] %% @spec (Host, Node) -> [Items] | []
%% Host = mod_pubsub:host() %% Host = mod_pubsub:host()
%% Node = mod_pubsub:pubsubNode() %% Node = mod_pubsub:pubsubNode()
@ -718,11 +663,9 @@ get_items(Host, Node, _From) ->
#pubsub_item{itemid = {'_', {Host, Node}}, _ = '_'}), #pubsub_item{itemid = {'_', {Host, Node}}, _ = '_'}),
{result, Items}. {result, Items}.
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
{Affiliation, Subscription} = State = get_state(Host, Node, jlib:jid_tolower(jlib:jid_remove_resource(JID))),
case get_state(Host, Node, jlib:jid_tolower(jlib:jid_remove_resource(JID))) of #pubsub_state{affiliation = Affiliation,
{result, #pubsub_state{affiliation = A, subscription = S}} -> {A, S}; subscription = Subscription} = State,
_ -> {none, none}
end,
Subscribed = not ((Subscription == none) or (Subscription == pending)), Subscribed = not ((Subscription == none) or (Subscription == pending)),
if if
%%SubID == "", ?? -> %%SubID == "", ?? ->
@ -770,11 +713,9 @@ get_item(Host, Node, ItemId) ->
{error, ?ERR_ITEM_NOT_FOUND} {error, ?ERR_ITEM_NOT_FOUND}
end. end.
get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) -> get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
{Affiliation, Subscription} = State = get_state(Host, Node, jlib:jid_tolower(jlib:jid_remove_resource(JID))),
case get_state(Host, Node, jlib:jid_tolower(jlib:jid_remove_resource(JID))) of #pubsub_state{affiliation = Affiliation,
{result, #pubsub_state{affiliation = A, subscription = S}} -> {A, S}; subscription = Subscription} = State,
_ -> {none, none}
end,
Subscribed = not ((Subscription == none) or (Subscription == pending)), Subscribed = not ((Subscription == none) or (Subscription == pending)),
if if
%%SubID == "", ?? -> %%SubID == "", ?? ->
@ -816,6 +757,18 @@ set_item(Item) when is_record(Item, pubsub_item) ->
set_item(_) -> set_item(_) ->
{error, ?ERR_INTERNAL_SERVER_ERROR}. {error, ?ERR_INTERNAL_SERVER_ERROR}.
%% @spec (ItemId) -> ok | {error, Reason::stanzaError()}
%% Host = mod_pubsub:host()
%% Node = mod_pubsub:pubsubNode()
%% ItemId = string()
%% @doc <p>Delete an item from database.</p>
del_item(Host, Node, ItemId) ->
mnesia:delete({pubsub_item, {ItemId, {Host, Node}}}).
del_items(Host, Node, ItemIds) ->
lists:foreach(fun(ItemId) ->
del_item(Host, Node, ItemId)
end, ItemIds).
%% @doc <p>Return the name of the node if known: Default is to return %% @doc <p>Return the name of the node if known: Default is to return
%% node id.</p> %% node id.</p>
get_item_name(_Host, _Node, Id) -> get_item_name(_Host, _Node, Id) ->

View File

@ -180,15 +180,9 @@ get_affiliation(_Host, Node, Owner) ->
set_affiliation(_Host, Node, Owner, Affiliation) -> set_affiliation(_Host, Node, Owner, Affiliation) ->
OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)), OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
Record = case get_state(OwnerKey, Node, OwnerKey) of State = get_state(OwnerKey, Node, OwnerKey),
{error, ?ERR_ITEM_NOT_FOUND} -> set_state(State#pubsub_state{affiliation = Affiliation}),
#pubsub_state{stateid = {OwnerKey, {OwnerKey, Node}}, ok.
affiliation = Affiliation};
{result, State} ->
State#pubsub_state{affiliation = Affiliation}
end,
set_state(Record),
ok.
get_entity_subscriptions(_Host, _Owner) -> get_entity_subscriptions(_Host, _Owner) ->
{result, []}. {result, []}.

View File

@ -72,7 +72,7 @@
%%% lserver = string(), %%% lserver = string(),
%%% lresource = string()}. %%% lresource = string()}.
%%% @type usr() = {User::string(), Server::string(), Resource::string()}. %%% @type ljid() = {User::string(), Server::string(), Resource::string()}.
%%% @type affiliation() = none | owner | publisher | outcast. %%% @type affiliation() = none | owner | publisher | outcast.
%%% @type subscription() = none | pending | unconfigured | subscribed. %%% @type subscription() = none | pending | unconfigured | subscribed.
@ -81,7 +81,7 @@
%%% nodeid = {Host::host(), Node::pubsubNode()}, %%% nodeid = {Host::host(), Node::pubsubNode()},
%%% parentid = {Host::host(), Node::pubsubNode()}, %%% parentid = {Host::host(), Node::pubsubNode()},
%%% type = nodeType(), %%% type = nodeType(),
%%% owners = [usr()], %%% owners = [ljid()],
%%% options = [nodeOption()]}. %%% options = [nodeOption()]}.
%%% <p>This is the format of the <tt>nodes</tt> table. The type of the table %%% <p>This is the format of the <tt>nodes</tt> table. The type of the table
%%% is: <tt>set</tt>,<tt>ram/disc</tt>.</p> %%% is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
@ -94,7 +94,7 @@
}). }).
%%% @type pubsubState() = #pubsub_state{ %%% @type pubsubState() = #pubsub_state{
%%% stateid = {jid(), {Host::host(), Node::pubsubNode()}}, %%% stateid = {ljid(), {Host::host(), Node::pubsubNode()}},
%%% items = [ItemId::string()], %%% items = [ItemId::string()],
%%% affiliation = affiliation(), %%% affiliation = affiliation(),
%%% subscription = subscription()}. %%% subscription = subscription()}.
@ -108,8 +108,8 @@
%% @type pubsubItem() = #pubsub_item{ %% @type pubsubItem() = #pubsub_item{
%% itemid = {ItemId::string(), {Host::host(),Node::pubsubNode()}}, %% itemid = {ItemId::string(), {Host::host(),Node::pubsubNode()}},
%% creation = {JID::jid(), now()}, %% creation = {ljid(), now()},
%% modification = {JID::jid(), now()}, %% modification = {ljid(), now()},
%% payload = XMLContent::string()}. %% payload = XMLContent::string()}.
%%% <p>This is the format of the <tt>published items</tt> table. The type of the %%% <p>This is the format of the <tt>published items</tt> table. The type of the
%%% table is: <tt>set</tt>,<tt>disc</tt>,<tt>fragmented</tt>.</p> %%% table is: <tt>set</tt>,<tt>disc</tt>,<tt>fragmented</tt>.</p>