lists:foreach(fun(Type) ->
{result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, JID]),
lists:foreach(
- fun({Node, subscribed}) ->
+ fun({Node, subscribed, SubJID}) ->
case tree_action(Host, get_node, [Host, Node]) of
#pubsub_node{options = Options} ->
case get_option(Options, send_last_published_item) of
on_sub_and_presence ->
- send_last_item(Host, Node, LJID);
+ send_last_item(Host, Node, SubJID);
_ ->
ok
end;
handle_cast({remove_user, LUser, LServer}, State) ->
Host = State#state.host,
Owner = jlib:make_jid(LUser, LServer, ""),
- OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
%% remove user's subscriptions
lists:foreach(fun(Type) ->
{result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, Owner]),
lists:foreach(fun
- ({Node, subscribed}) ->
- JID = jlib:jid_to_string(Owner),
+ ({Node, subscribed, JID}) ->
unsubscribe_node(Host, Node, Owner, JID, all);
(_) ->
ok
%% remove user's PEP nodes
lists:foreach(fun(#pubsub_node{nodeid={NodeKey, NodeName}}) ->
delete_node(NodeKey, NodeName, Owner)
- end, tree_action(Host, get_nodes, [OwnerKey])),
+ end, tree_action(Host, get_nodes, [jlib:jid_tolower(Owner)])),
%% remove user's nodes
delete_node(Host, ["home", LServer, LUser], Owner),
{noreply, State};
%%<li>The node does not exist.</li>
%%<li>The request specifies a subscription ID that is not valid or current.</li>
%%</ul>
-unsubscribe_node(Host, Node, From, JID, SubId) ->
+unsubscribe_node(Host, Node, From, JID, SubId) when is_list(JID) ->
Subscriber = case jlib:string_to_jid(JID) of
error -> {"", "", ""};
J -> jlib:jid_tolower(J)
end,
+ unsubscribe_node(Host, Node, From, Subscriber, SubId);
+unsubscribe_node(Host, Node, From, Subscriber, SubId) ->
case node_action(Host, Node, unsubscribe_node,
[Host, Node, From, Subscriber, SubId]) of
{error, Error} ->
%% Service does not support retreive subscriptions
{{error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "retrieve-subscriptions")}, Acc};
true ->
- {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, JID]),
+ Subscriber = jlib:jid_remove_resource(JID),
+ {result, Subscriptions} = node_action(Type, get_entity_subscriptions, [Host, Subscriber]),
{Status, [Subscriptions|Acc]}
end
end, {ok, []}, Plugins),
broadcast_stanza(Host, NodeOpts, States, Stanza) ->
PresenceDelivery = get_option(NodeOpts, presence_based_delivery),
- BroadcastAll = get_option(NodeOpts, broadcast_all_resources),
+ BroadcastAll = get_option(NodeOpts, broadcast_all_resources), %% XXX this is not standard
From = service_jid(Host),
lists:foreach(fun(#pubsub_state{stateid = {LJID, _}, subscription = Subs}) ->
case is_to_deliver(LJID, Subs, PresenceDelivery) of
["create-nodes",
"auto-create",
"delete-nodes",
- "delete-any",
"instant-nodes",
"manage-subscriptions",
"modify-affiliations",
%% <p>In the default plugin module, the record is unchanged.</p>
subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup) ->
- SubscriberKey = jlib:jid_tolower(jlib:jid_remove_resource(Subscriber)),
- Authorized = (jlib:jid_tolower(jlib:jid_remove_resource(Sender)) == SubscriberKey),
- State = get_state(Host, Node, SubscriberKey),
- #pubsub_state{affiliation = Affiliation,
- subscription = Subscription} = State,
+ SubKey = jlib:jid_tolower(Subscriber),
+ GenKey = jlib:jid_remove_resource(SubKey),
+ Authorized = (jlib:jid_tolower(jlib:jid_remove_resource(Sender)) == GenKey),
+ GenState = get_state(Host, Node, GenKey),
+ SubState = case SubKey of
+ GenKey -> GenState;
+ _ -> get_state(Host, Node, SubKey)
+ end,
+ Affiliation = GenState#pubsub_state.affiliation,
+ Subscription = SubState#pubsub_state.subscription,
if
not Authorized ->
%% JIDs do not match
true ->
subscribed
end,
- set_state(State#pubsub_state{subscription = NewSubscription}),
+ set_state(SubState#pubsub_state{subscription = NewSubscription}),
case NewSubscription of
subscribed ->
case SendLast of
%% Reason = mod_pubsub:stanzaError()
%% @doc <p>Unsubscribe the <tt>Subscriber</tt> from the <tt>Node</tt>.</p>
unsubscribe_node(Host, Node, Sender, Subscriber, _SubId) ->
- SubscriberKey = jlib:jid_tolower(jlib:jid_remove_resource(Subscriber)),
- Authorized = (jlib:jid_tolower(jlib:jid_remove_resource(Sender)) == SubscriberKey),
- State = get_state(Host, Node, SubscriberKey),
+ SubKey = jlib:jid_tolower(Subscriber),
+ GenKey = jlib:jid_remove_resource(SubKey),
+ Authorized = (jlib:jid_tolower(jlib:jid_remove_resource(Sender)) == GenKey),
+ GenState = get_state(Host, Node, GenKey),
+ SubState = case SubKey of
+ GenKey -> GenState;
+ _ -> get_state(Host, Node, SubKey)
+ end,
+ Affiliation = GenState#pubsub_state.affiliation,
+ Subscription = SubState#pubsub_state.subscription,
if
%% Entity did not specify SubID
%%SubID == "", ?? ->
%%InvalidSubID ->
%% {error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
%% Requesting entity is not a subscriber
- State#pubsub_state.subscription == none ->
+ Subscription == none ->
{error, ?ERR_EXTENDED(?ERR_UNEXPECTED_REQUEST, "not-subscribed")};
%% Requesting entity is prohibited from unsubscribing entity
- (not Authorized) and (State#pubsub_state.affiliation =/= owner) ->
+ (not Authorized) and (Affiliation =/= owner) ->
{error, ?ERR_FORBIDDEN};
%% Was just subscriber, remove the record
- State#pubsub_state.affiliation == none ->
- del_state(State#pubsub_state.stateid),
+ Affiliation == none ->
+ del_state(SubState#pubsub_state.stateid),
{result, default};
true ->
- set_state(State#pubsub_state{subscription = none}),
+ %% TODO, may require better clean
+ set_state(SubState#pubsub_state{subscription = none}),
{result, default}
end.
%% </p>
%% <p>In the default plugin module, the record is unchanged.</p>
publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
- PublisherKey = jlib:jid_tolower(jlib:jid_remove_resource(Publisher)),
- State = get_state(Host, Node, PublisherKey),
- #pubsub_state{affiliation = Affiliation,
- subscription = Subscription} = State,
+ SubKey = jlib:jid_tolower(Publisher),
+ GenKey = jlib:jid_remove_resource(SubKey),
+ GenState = get_state(Host, Node, GenKey),
+ SubState = case SubKey of
+ GenKey -> GenState;
+ _ -> get_state(Host, Node, SubKey)
+ end,
+ Affiliation = GenState#pubsub_state.affiliation,
+ Subscription = SubState#pubsub_state.subscription,
if
not ((PublishModel == open)
or ((PublishModel == publishers)
%% Entity does not have sufficient privileges to publish to node
{error, ?ERR_FORBIDDEN};
true ->
- PubId = {PublisherKey, now()},
+ PubId = {SubKey, now()},
Item = case get_item(Host, Node, ItemId) of
{result, OldItem} ->
OldItem#pubsub_item{modification = PubId,
payload = Payload};
_ ->
#pubsub_item{itemid = {ItemId, {Host, Node}},
- creation = PubId,
+ creation = {GenKey, now()},
modification = PubId,
payload = Payload}
end,
- Items = [ItemId | State#pubsub_state.items--[ItemId]],
+ Items = [ItemId | GenState#pubsub_state.items--[ItemId]],
{result, {NI, OI}} = remove_extra_items(
Host, Node, MaxItems, Items),
if MaxItems > 0 -> set_item(Item);
true -> ok
end,
- set_state(State#pubsub_state{items = NI}),
+ set_state(GenState#pubsub_state{items = NI}),
{result, {default, broadcast, OI}}
end.
%% <p>Default plugin: The user performing the deletion must be the node owner
%% or a publisher.</p>
delete_item(Host, Node, Publisher, ItemId) ->
- PublisherKey = jlib:jid_tolower(jlib:jid_remove_resource(Publisher)),
- State = get_state(Host, Node, PublisherKey),
- #pubsub_state{affiliation = Affiliation, items = Items} = State,
+ SubKey = jlib:jid_tolower(Publisher),
+ GenKey = jlib:jid_remove_resource(SubKey),
+ GenState = get_state(Host, Node, GenKey),
+ #pubsub_state{affiliation = Affiliation, items = Items} = GenState,
Allowed = (Affiliation == publisher) orelse (Affiliation == owner)
orelse case get_item(Host, Node, ItemId) of
- {result, #pubsub_item{creation = {PublisherKey, _}}} -> true;
+ {result, #pubsub_item{creation = {GenKey, _}}} -> true;
_ -> false
end,
if
{result, _} ->
del_item(Host, Node, ItemId),
NewItems = lists:delete(ItemId, Items),
- set_state(State#pubsub_state{items = NewItems}),
+ set_state(GenState#pubsub_state{items = NewItems}),
{result, {default, broadcast}};
_ ->
%% Non-existent node or item
%% @doc <p>Purge all node items.</p>
%% <p>Default plugin: The user performing the deletion must be the node owner.</p>
purge_node(Host, Node, Owner) ->
- OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
- case get_state(Host, Node, OwnerKey) of
+ SubKey = jlib:jid_tolower(Owner),
+ GenKey = jlib:jid_remove_resource(SubKey),
+ GenState = get_state(Host, Node, GenKey),
+ case GenState of
#pubsub_state{items = Items, affiliation = owner} ->
del_items(Host, Node, Items),
{result, {default, broadcast}};
%% that will be added to the affiliation stored in the main
%% <tt>pubsub_state</tt> table.</p>
get_entity_affiliations(Host, Owner) ->
- OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
+ SubKey = jlib:jid_tolower(Owner),
+ GenKey = jlib:jid_remove_resource(SubKey),
States = mnesia:match_object(
- #pubsub_state{stateid = {OwnerKey, {Host, '_'}}, _ = '_'}),
+ #pubsub_state{stateid = {GenKey, {Host, '_'}}, _ = '_'}),
Tr = fun(#pubsub_state{stateid = {_, {_, N}}, affiliation = A}) ->
{N, A}
end,
{result, lists:map(Tr, States)}.
get_affiliation(Host, Node, Owner) ->
- OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
- State = get_state(Host, Node, OwnerKey),
- {result, State#pubsub_state.affiliation}.
+ SubKey = jlib:jid_tolower(Owner),
+ GenKey = jlib:jid_remove_resource(SubKey),
+ GenState = get_state(Host, Node, GenKey),
+ {result, GenState#pubsub_state.affiliation}.
set_affiliation(Host, Node, Owner, Affiliation) ->
- OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
- State = get_state(Host, Node, OwnerKey),
- set_state(State#pubsub_state{affiliation = Affiliation}),
+ SubKey = jlib:jid_tolower(Owner),
+ GenKey = jlib:jid_remove_resource(SubKey),
+ GenState = get_state(Host, Node, GenKey),
+ set_state(GenState#pubsub_state{affiliation = Affiliation}),
ok.
%% @spec (Host, Ownner) -> [{Node,Subscription}]
%% that will be added to the affiliation stored in the main
%% <tt>pubsub_state</tt> table.</p>
get_entity_subscriptions(Host, Owner) ->
- OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
- States = mnesia:match_object(
- #pubsub_state{stateid = {OwnerKey, {Host, '_'}}, _ = '_'}),
- Tr = fun(#pubsub_state{stateid = {_, {_, N}}, subscription = S}) ->
- {N, S}
+ States = case jlib:jid_tolower(Owner) of
+ {U, D, ""} -> mnesia:match_object(
+ #pubsub_state{stateid = {{U, D, '_'}, {Host, '_'}}, _ = '_'});
+ {U, D, R} -> mnesia:match_object(
+ #pubsub_state{stateid = {{U, D, ""}, {Host, '_'}}, _ = '_'})
+ ++ mnesia:match_object(
+ #pubsub_state{stateid = {{U, D, R}, {Host, '_'}}, _ = '_'})
+ end,
+ Tr = fun(#pubsub_state{stateid = {J, {_, N}}, subscription = S}) ->
+ {N, S, J}
end,
{result, lists:map(Tr, States)}.
{result, lists:map(Tr, States)}.
get_subscription(Host, Node, Owner) ->
- OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
- State = get_state(Host, Node, OwnerKey),
- {result, State#pubsub_state.subscription}.
+ SubKey = jlib:jid_tolower(Owner),
+ SubState = get_state(Host, Node, SubKey),
+ {result, SubState#pubsub_state.subscription}.
set_subscription(Host, Node, Owner, Subscription) ->
- OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
- State = get_state(Host, Node, OwnerKey),
- set_state(State#pubsub_state{subscription = Subscription}),
+ SubKey = jlib:jid_tolower(Owner),
+ SubState = get_state(Host, Node, SubKey),
+ set_state(SubState#pubsub_state{subscription = Subscription}),
ok.
%% @spec (Host, Node) -> [States] | []
#pubsub_item{itemid = {'_', {Host, Node}}, _ = '_'}),
{result, Items}.
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
- State = get_state(Host, Node, jlib:jid_tolower(jlib:jid_remove_resource(JID))),
- #pubsub_state{affiliation = Affiliation,
- subscription = Subscription} = State,
- Subscribed = not ((Subscription == none) or (Subscription == pending)),
+ SubKey = jlib:jid_tolower(JID),
+ GenKey = jlib:jid_remove_resource(SubKey),
+ GenState = get_state(Host, Node, GenKey),
+ Affiliation = GenState#pubsub_state.affiliation,
if
%%SubID == "", ?? ->
%% Entity has multiple subscriptions to the node but does not specify a subscription ID
Affiliation == outcast ->
%% Requesting entity is blocked
{error, ?ERR_FORBIDDEN};
- (AccessModel == open) and (not Subscribed) ->
- %% Entity is not subscribed
- {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "not-subscribed")};
(AccessModel == presence) and (not PresenceSubscription) ->
%% Entity is not authorized to create a subscription (presence subscription required)
{error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "presence-subscription-required")};
{error, ?ERR_ITEM_NOT_FOUND}
end.
get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
- State = get_state(Host, Node, jlib:jid_tolower(jlib:jid_remove_resource(JID))),
- #pubsub_state{affiliation = Affiliation,
- subscription = Subscription} = State,
- Subscribed = not ((Subscription == none) or (Subscription == pending)),
+ SubKey = jlib:jid_tolower(JID),
+ GenKey = jlib:jid_remove_resource(SubKey),
+ GenState = get_state(Host, Node, GenKey),
+ Affiliation = GenState#pubsub_state.affiliation,
if
%%SubID == "", ?? ->
%% Entity has multiple subscriptions to the node but does not specify a subscription ID
Affiliation == outcast ->
%% Requesting entity is blocked
{error, ?ERR_FORBIDDEN};
- (AccessModel == open) and (not Subscribed) ->
- %% Entity is not subscribed
- {error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "not-subscribed")};
(AccessModel == presence) and (not PresenceSubscription) ->
%% Entity is not authorized to create a subscription (presence subscription required)
{error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "presence-subscription-required")};