mirror of
https://github.com/processone/ejabberd.git
synced 2024-10-31 15:21:38 +01:00
571 lines
24 KiB
Erlang
571 lines
24 KiB
Erlang
%%% ====================================================================
|
|
%%% ``The contents of this file are subject to the Erlang Public License,
|
|
%%% Version 1.1, (the "License"); you may not use this file except in
|
|
%%% compliance with the License. You should have received a copy of the
|
|
%%% Erlang Public License along with this software. If not, it can be
|
|
%%% retrieved via the world wide web at http://www.erlang.org/.
|
|
%%%
|
|
%%% Software distributed under the License is distributed on an "AS IS"
|
|
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
|
%%% the License for the specific language governing rights and limitations
|
|
%%% under the License.
|
|
%%%
|
|
%%% The Initial Developer of the Original Code is ProcessOne.
|
|
%%% Portions created by ProcessOne are Copyright 2006-2013, ProcessOne
|
|
%%% All Rights Reserved.''
|
|
%%% This software is copyright 2006-2013, ProcessOne.
|
|
%%%
|
|
%%% @copyright 2006-2013 ProcessOne
|
|
%%% @author Karim Gemayel <karim.gemayel@process-one.net>
|
|
%%% [http://www.process-one.net/]
|
|
%%% @version {@vsn}, {@date} {@time}
|
|
%%% @end
|
|
%%% ====================================================================
|
|
|
|
%%% @headerfile "pubsub_dev.hrl"
|
|
|
|
-module(pubsub_hooks).
|
|
-author('karim.gemayel@process-one.net').
|
|
|
|
-compile(export_all).
|
|
|
|
-include("pubsub_dev.hrl").
|
|
|
|
-import(pubsub_tools,
|
|
[
|
|
get_option/2,
|
|
get_option/3,
|
|
get_value/2,
|
|
get_value/3,
|
|
set_value/3,
|
|
%%
|
|
check_access_model/3,
|
|
check_access_model/7,
|
|
check_publish_model/3,
|
|
is_contact_subscribed_to_node_owners/3,
|
|
is_contact_in_allowed_roster_groups/2,
|
|
has_subscriptions/1
|
|
]).
|
|
|
|
-import(pubsub_db_mnesia,
|
|
[
|
|
table/2
|
|
]).
|
|
|
|
%% 'node_config#send_last_published_item'
|
|
-spec(presence_online/3 ::
|
|
(
|
|
From :: xmpp_jid:entity_full(),
|
|
To :: xmpp_jid:entity_full(),
|
|
C2SPid :: pid())
|
|
-> 'ok'
|
|
).
|
|
|
|
presence_online(#jid{luser = U, lserver = S, lresource = R} = Jid, Jid, C2SPid) ->
|
|
?INFO_MSG("PRESENCE ONLINE From ~p ~n, To ~p ~n, C2SPid ~p ~n",
|
|
[Jid, Jid, C2SPid]),
|
|
Pubsub_Features = node_flat_dev:pubsub_features(),
|
|
case lists:member(<<"last-published">>, Pubsub_Features) of
|
|
true ->
|
|
spawn(?MODULE, last_published_items,
|
|
[_Host = <<"localhost">>, {U,S,R}]);
|
|
false ->
|
|
ok
|
|
end;
|
|
%%
|
|
presence_online(_, _, _) ->
|
|
ok.
|
|
|
|
|
|
%%
|
|
-spec(last_published_items/2 ::
|
|
(
|
|
Host :: xmpp_jid:raw_jid_component_bare(),
|
|
Entity :: xmpp_jid:usr_full())
|
|
-> 'ok'
|
|
).
|
|
|
|
last_published_items(Host, {U,S,_R} = Entity) ->
|
|
Table_Pubsub_State = table('pubsub_state', 'dev'),
|
|
Table_Pubsub_Node = table('pubsub_node', 'dev'),
|
|
Table_Pubsub_Last_Item = table('pubsub_last_item', 'dev'),
|
|
lists:foreach(fun
|
|
(State) ->
|
|
last_published_items(Host, Entity, Table_Pubsub_Node,
|
|
Table_Pubsub_Last_Item, State)
|
|
end,
|
|
mnesia:dirty_select(Table_Pubsub_State,
|
|
[{#pubsub_state_dev{
|
|
id = {{U,S,undefined}, '$1'},
|
|
affiliation = '$2',
|
|
access = '$3',
|
|
subscriptions = '$4',
|
|
_ = '_'
|
|
},
|
|
[{'=/=', '$2', 'outcast'},
|
|
{'=/=', '$3', 'pending'},
|
|
{'=/=', '$4', []}],
|
|
['$$']}])).
|
|
|
|
%%
|
|
-spec(last_published_items/5 ::
|
|
(
|
|
Host :: xmpp_jid:raw_jid_component_bare(),
|
|
Entity :: xmpp_jid:usr_full(),
|
|
Table_Pubsub_Node :: atom(),
|
|
Table_Pubsub_Last_Item :: atom(),
|
|
State :: [exmpp_pubsub:nodeIdx() |
|
|
'member' | 'owner' | 'publisher' |
|
|
_ |
|
|
exmpp_pubsub:subscriptions(),... ])
|
|
-> 'ok'
|
|
).
|
|
|
|
last_published_items(Host, {_, _, Online_Resource} = Entity,
|
|
Table_Pubsub_Node, Table_Pubsub_Last_Item,
|
|
[NodeIdx, Affiliation, _Access, Subscriptions]) ->
|
|
case mnesia:dirty_index_read(Table_Pubsub_Node, NodeIdx, idx) of
|
|
[#pubsub_node_dev{
|
|
id = {Pubsub_Host, NodeId},
|
|
owners = Node_Owners,
|
|
options = Node_Options
|
|
}] ->
|
|
case get_value(Node_Options, 'send_last_published_item') of
|
|
'on_sub_and_presence' ->
|
|
case mnesia:dirty_read(Table_Pubsub_Last_Item, NodeIdx) of
|
|
[#pubsub_last_item_dev{
|
|
id = ItemId,
|
|
creation = {DateTime, Publisher},
|
|
payload = Payload,
|
|
options = Item_Options
|
|
}] ->
|
|
spawn(pubsub_broadcast, broadcast_publish_last2,
|
|
[Host, Pubsub_Host, NodeId, Node_Options,
|
|
Node_Owners,
|
|
[{ItemId, Item_Options, Payload, Publisher, DateTime}],
|
|
Entity, Affiliation,
|
|
lists:foldl(fun
|
|
({Subscription_State, SubId, Resource, Subscription_Options},
|
|
Acc)
|
|
when Subscription_State =/= 'pending'
|
|
andalso (Resource == undefined
|
|
orelse
|
|
Resource == Online_Resource) ->
|
|
[{Subscription_State, SubId,
|
|
Online_Resource, Subscription_Options}
|
|
| Acc];
|
|
(_Subscription, Acc) ->
|
|
Acc
|
|
end, [], Subscriptions)]);
|
|
_ ->
|
|
ok
|
|
end;
|
|
_ ->
|
|
ok
|
|
end;
|
|
_ ->
|
|
ok
|
|
end.
|
|
|
|
%% 'node_config#purge_offline'
|
|
%% 'node_config#tempsub'
|
|
%% 'subscribe_options#expire'
|
|
|
|
-spec(presence_offline/3 ::
|
|
(
|
|
_ :: _,
|
|
Jid :: xmpp_jid:entity_full(),
|
|
_ :: _)
|
|
-> 'ok'
|
|
).
|
|
|
|
presence_offline({_DateTime, _Pid},
|
|
#jid{luser = U, lserver = S, lresource = Offline_Resource} = _Jid, _) ->
|
|
Host = <<"localhost">>,
|
|
Pubsub_Features = node_flat_dev:pubsub_features(),
|
|
Subscribe = lists:member(<<"subscribe">>, Pubsub_Features),
|
|
Leased_Subscription = lists:member(<<"leased-subscription">>, Pubsub_Features),
|
|
Purge_Nodes = lists:member(<<"purge-nodes">>, Pubsub_Features),
|
|
Persistent_Items = lists:member(<<"persistent-items">>, Pubsub_Features),
|
|
Subscription_Notifications = lists:member(<<"subscription-notifications">>,
|
|
Pubsub_Features),
|
|
Table_Pubsub_State = table('pubsub_state', 'dev'),
|
|
Table_Pubsub_Node = table('pubsub_node', 'dev'),
|
|
Online_Resources = case ejabberd_sm:get_user_resources(U, S) of
|
|
[] -> false;
|
|
_ -> true
|
|
end,
|
|
lists:foreach(fun
|
|
(Pubsub_State) ->
|
|
presence_offline(Host,
|
|
_Entity = {U,S,undefined},
|
|
Table_Pubsub_State,
|
|
Pubsub_State,
|
|
Table_Pubsub_Node,
|
|
Offline_Resource,
|
|
Online_Resources,
|
|
{Subscribe,
|
|
Leased_Subscription,
|
|
Purge_Nodes,
|
|
Persistent_Items,
|
|
Subscription_Notifications})
|
|
end,
|
|
mnesia:dirty_match_object(Table_Pubsub_State,
|
|
#pubsub_state_dev{
|
|
id = {{U,S,undefined}, '_'},
|
|
_ = '_'
|
|
})).
|
|
|
|
%%
|
|
-spec(presence_offline/8 ::
|
|
(
|
|
Host :: xmpp_jid:raw_jid_component_bare(),
|
|
Entity :: xmpp_jid:usr_bare(),
|
|
Table_Pubsub_State :: atom(),
|
|
Pubsub_State :: mod_pubsub_dev:pubsub_state(),
|
|
Table_Pubsub_Node :: atom(),
|
|
Offline_Resource :: xmpp_jid:resource_jid(),
|
|
Online_Resources :: boolean(),
|
|
Pubsub_Features :: {Subscribe :: boolean(),
|
|
Leased_Subscription :: boolean(),
|
|
Purge_Nodes :: boolean(),
|
|
Persistent_Items :: boolean(),
|
|
Subscription_Notifications :: boolean()})
|
|
-> 'ok'
|
|
).
|
|
|
|
presence_offline(Host, Entity, Table_Pubsub_State, Pubsub_State,
|
|
Table_Pubsub_Node, Offline_Resource, Online_Resources,
|
|
{Subscribe, Leased_Subscription, Purge_Nodes, Persistent_Items,
|
|
Subscription_Notifications}) ->
|
|
case
|
|
mnesia:dirty_index_read(Table_Pubsub_Node,
|
|
Pubsub_State#pubsub_state_dev.nodeidx, idx)
|
|
of
|
|
[#pubsub_node_dev{id = {Pubsub_Host, NodeId}} = Pubsub_Node] ->
|
|
Node_Options = Pubsub_Node#pubsub_node_dev.options,
|
|
|
|
case
|
|
Subscribe == true
|
|
andalso
|
|
get_value(Node_Options, 'tempsub') == true
|
|
of
|
|
true ->
|
|
case
|
|
filter_tempsub_subscriptions(
|
|
get_value(Node_Options, 'notify_sub'),
|
|
Pubsub_State#pubsub_state_dev.subscriptions,
|
|
Offline_Resource, Online_Resources, {[], []})
|
|
of
|
|
%%
|
|
{_Unexpired_Subscriptions, [] = _Expired_Subscriptions} ->
|
|
ok;
|
|
%%
|
|
{[] = _Unexpired_Subscriptions, Expired_Subscriptions}
|
|
when Pubsub_State#pubsub_state_dev.affiliation == 'member'
|
|
andalso Pubsub_State#pubsub_state_dev.itemids == [] ->
|
|
mnesia:dirty_delete_object(Table_Pubsub_State,
|
|
Pubsub_State),
|
|
Notification_Type = get_value(Node_Options,
|
|
'notification_type', 'headline'),
|
|
notify_subscriptions(Host, Pubsub_Host,
|
|
Entity, NodeId, Notification_Type,
|
|
_Recipients = case Subscription_Notifications of
|
|
true ->
|
|
case
|
|
lists:member(Entity,
|
|
Pubsub_Node#pubsub_node_dev.owners)
|
|
of
|
|
true ->
|
|
Pubsub_Node#pubsub_node_dev.owners;
|
|
false ->
|
|
[Entity
|
|
| Pubsub_Node#pubsub_node_dev.owners]
|
|
end;
|
|
false ->
|
|
Pubsub_Node#pubsub_node_dev.owners
|
|
end,
|
|
Expired_Subscriptions),
|
|
ok;
|
|
%%
|
|
{Unexpired_Subscriptions, Expired_Subscriptions} ->
|
|
mnesia:dirty_write(Table_Pubsub_State,
|
|
Pubsub_State#pubsub_state_dev{
|
|
subscriptions = Unexpired_Subscriptions
|
|
}),
|
|
Notification_Type = get_value(Node_Options,
|
|
'notification_type', 'headline'),
|
|
notify_subscriptions(Host, Pubsub_Host,
|
|
Entity, NodeId, Notification_Type,
|
|
_Recipients = case Subscription_Notifications of
|
|
true ->
|
|
case
|
|
lists:member(Entity,
|
|
Pubsub_Node#pubsub_node_dev.owners)
|
|
of
|
|
true ->
|
|
Pubsub_Node#pubsub_node_dev.owners;
|
|
false ->
|
|
[Entity
|
|
| Pubsub_Node#pubsub_node_dev.owners]
|
|
end;
|
|
false ->
|
|
Pubsub_Node#pubsub_node_dev.owners
|
|
end,
|
|
Expired_Subscriptions),
|
|
ok
|
|
end;
|
|
_ ->
|
|
case Subscribe == true andalso Leased_Subscription == true of
|
|
true ->
|
|
case
|
|
filter_expired_subscriptions(
|
|
get_value(Node_Options, 'notify_sub'),
|
|
Pubsub_State#pubsub_state_dev.subscriptions,
|
|
Offline_Resource, Online_Resources, {[], []})
|
|
of
|
|
%%
|
|
{_Unexpired_Subscriptions, [] = _Expired_Subscriptions} ->
|
|
ok;
|
|
%%
|
|
{[] = _Unexpired_Subscriptions, Expired_Subscriptions}
|
|
when Pubsub_State#pubsub_state_dev.affiliation == 'member' ->
|
|
mnesia:dirty_delete_object(Table_Pubsub_State,
|
|
Pubsub_State),
|
|
Notification_Type = get_value(Node_Options,
|
|
'notification_type', 'headline'),
|
|
notify_subscriptions(Host, Pubsub_Host,
|
|
Entity, NodeId, Notification_Type,
|
|
_Recipients = case
|
|
Subscription_Notifications
|
|
of
|
|
true ->
|
|
case
|
|
lists:member(Entity,
|
|
Pubsub_Node#pubsub_node_dev.owners)
|
|
of
|
|
true ->
|
|
Pubsub_Node#pubsub_node_dev.owners;
|
|
false ->
|
|
[Entity
|
|
|Pubsub_Node#pubsub_node_dev.owners]
|
|
end;
|
|
false ->
|
|
Pubsub_Node#pubsub_node_dev.owners
|
|
end,
|
|
Expired_Subscriptions),
|
|
ok;
|
|
%%
|
|
{Unexpired_Subscriptions, Expired_Subscriptions} ->
|
|
mnesia:dirty_write(Table_Pubsub_State,
|
|
Pubsub_State#pubsub_state_dev{
|
|
subscriptions = Unexpired_Subscriptions
|
|
}),
|
|
Notification_Type = get_value(Node_Options,
|
|
'notification_type', 'headline'),
|
|
notify_subscriptions(Host, Pubsub_Host,
|
|
Entity, NodeId, Notification_Type,
|
|
_Recipients = case
|
|
Subscription_Notifications
|
|
of
|
|
true ->
|
|
case
|
|
lists:member(Entity,
|
|
Pubsub_Node#pubsub_node_dev.owners)
|
|
of
|
|
true ->
|
|
Pubsub_Node#pubsub_node_dev.owners;
|
|
false ->
|
|
[Entity
|
|
| Pubsub_Node#pubsub_node_dev.owners]
|
|
end;
|
|
false ->
|
|
Pubsub_Node#pubsub_node_dev.owners
|
|
end,
|
|
Expired_Subscriptions),
|
|
ok
|
|
end;
|
|
false ->
|
|
ok
|
|
end
|
|
end;
|
|
[] ->
|
|
ok
|
|
end.
|
|
|
|
%%
|
|
-spec(notify_subscriptions/7 ::
|
|
(
|
|
Host :: xmpp_jid:raw_jid_component_bare(),
|
|
Pubsub_Host :: exmpp_pubsub:host(),
|
|
Entity :: xmpp_jid:usr_bare(),
|
|
NodeId :: exmpp_pubsub:nodeId(),
|
|
Notification_Type :: 'message' | 'headline',
|
|
Recipients :: [Entity::xmpp_jid:usr_bare(),...],
|
|
Subscriptions :: [Subscription::exmpp_pubsub:subscription(),...])
|
|
-> 'ok'
|
|
).
|
|
|
|
notify_subscriptions(Host, Pubsub_Host, {U,S,_} = _Entity, NodeId,
|
|
Notification_Type, Recipients, Subscriptions) ->
|
|
Pubsub_Component_Jid = jlib:make_jid(<<>>, Pubsub_Host, <<>>),
|
|
Jids = [pubsub_tools:make_jid(Recipient) || Recipient <- Recipients],
|
|
lists:foreach(fun
|
|
({_, SubId, Resource, _}) ->
|
|
Subscriber = jlib:jid_to_string({U,S,Resource}),
|
|
lists:foreach(fun
|
|
(Recipient) ->
|
|
spawn(pubsub_broadcast, notify_subscription,
|
|
[Host, NodeId, Pubsub_Component_Jid, Recipient,
|
|
Notification_Type, {Subscriber, 'none', SubId}])
|
|
end, Jids)
|
|
end, Subscriptions).
|
|
|
|
%%
|
|
filter_purged_offline_itemids([Publisher_ItemId | Publisher_ItemIds],
|
|
Table_Pubsub_Item, NodeIdx, {U,S,R} = _Entity,
|
|
{Node_ItemIds, Unpurged_ItemIds, Purged_ItemIds}) ->
|
|
filter_purged_offline_itemids(Publisher_ItemIds, Table_Pubsub_Item, NodeIdx,
|
|
{U,S,R},
|
|
case
|
|
mnesia:dirty_index_match_object(Table_Pubsub_Item,
|
|
#pubsub_item_dev{
|
|
id = {Publisher_ItemId, NodeIdx},
|
|
nodeidx = NodeIdx,
|
|
_ = '_'
|
|
},
|
|
nodeidx)
|
|
of
|
|
[#pubsub_item_dev{creation = {_DateTime, {U,S,_}}} = Pubsub_Item] ->
|
|
mnesia:dirty_delete_object(Table_Pubsub_Item, Pubsub_Item);
|
|
_ ->
|
|
{Node_ItemIds,
|
|
[Publisher_ItemId | Unpurged_ItemIds],
|
|
Purged_ItemIds}
|
|
end).
|
|
|
|
|
|
%%
|
|
-spec(filter_tempsub_subscriptions/5 ::
|
|
(
|
|
Notify_Sub :: boolean() | 'none',
|
|
Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
|
Offline_Resource :: xmpp_jid:resource_jid(),
|
|
Online_Resources :: boolean(),
|
|
Filtered_TempSub_Subscriptions :: {
|
|
Unexpired_Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
|
Expired_Subscriptions :: [] | exmpp_pubsub:subscriptions()
|
|
})
|
|
-> Filtered_TempSub_Subscriptions :: {
|
|
Unexpired_Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
|
Expired_Subscriptions :: [] | exmpp_pubsub:subscriptions()
|
|
}
|
|
).
|
|
|
|
filter_tempsub_subscriptions(_Notify_Sub, [] = _Subscriptions,
|
|
_Offline_Resource, _Online_Resources, Filtered_TempSub_Subscriptions) ->
|
|
Filtered_TempSub_Subscriptions;
|
|
%%
|
|
filter_tempsub_subscriptions(Notify_Sub,
|
|
[{Subscription_State, SubId, Resource, Subscription_Options} | Subscriptions],
|
|
Offline_Resource, Online_Resources,
|
|
{Unexpired_Subscriptions, Expired_Subscriptions})
|
|
when ((Online_Resources == false
|
|
andalso
|
|
(Resource == undefined orelse Resource == Offline_Resource))
|
|
orelse
|
|
(Online_Resources == true
|
|
andalso
|
|
Resource == Offline_Resource)) ->
|
|
filter_tempsub_subscriptions(Notify_Sub, Subscriptions, Offline_Resource,
|
|
Online_Resources,
|
|
{Unexpired_Subscriptions,
|
|
_Expired_Subscriptions = case Notify_Sub of
|
|
true ->
|
|
[{Subscription_State, SubId, Resource, Subscription_Options}
|
|
| Expired_Subscriptions];
|
|
_ ->
|
|
Expired_Subscriptions
|
|
end});
|
|
%%
|
|
filter_tempsub_subscriptions(Notify_Sub, [Subscription | Subscriptions],
|
|
Offline_Resource, Online_Resources,
|
|
{Unexpired_Subscriptions, Expired_Subscriptions}) ->
|
|
filter_tempsub_subscriptions(Notify_Sub, Subscriptions, Offline_Resource,
|
|
Online_Resources,
|
|
{[Subscription | Unexpired_Subscriptions], Expired_Subscriptions}).
|
|
|
|
%%
|
|
-spec(filter_expired_subscriptions/5 ::
|
|
(
|
|
Notify_Sub :: boolean() | 'none',
|
|
Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
|
Offline_Resource :: xmpp_jid:resource_jid(),
|
|
Online_Resources :: boolean(),
|
|
Filtered_Expired_Subscriptions :: {
|
|
Unexpired_Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
|
Expired_Subscriptions :: [] | exmpp_pubsub:subscriptions()
|
|
})
|
|
-> Filtered_Expired_Subscriptions :: {
|
|
Unexpired_Subscriptions :: [] | exmpp_pubsub:subscriptions(),
|
|
Expired_Subscriptions :: [] | exmpp_pubsub:subscriptions()
|
|
}
|
|
).
|
|
|
|
filter_expired_subscriptions(_Notify_Sub, [] = _Subscriptions, _Offline_Resource,
|
|
_Online_Resources, Filtered_Expired_Subscriptions) ->
|
|
Filtered_Expired_Subscriptions;
|
|
%%
|
|
filter_expired_subscriptions(Notify_Sub,
|
|
[{Subscription_State, SubId, Resource, Subscription_Options} | Subscriptions],
|
|
Offline_Resource, Online_Resources,
|
|
{Unexpired_Subscriptions, Expired_Subscriptions})
|
|
when Subscription_Options =/= []
|
|
andalso ((Online_Resources == false
|
|
andalso
|
|
(Resource == undefined orelse Resource == Offline_Resource))
|
|
orelse
|
|
(Online_Resources == true
|
|
andalso
|
|
Resource == Offline_Resource)) ->
|
|
filter_expired_subscriptions(Notify_Sub, Subscriptions, Offline_Resource,
|
|
Online_Resources,
|
|
case get_value(Subscription_Options, 'expire') of
|
|
'presence' ->
|
|
{Unexpired_Subscriptions,
|
|
_Expired_Subscriptions = case Notify_Sub of
|
|
true ->
|
|
[{Subscription_State, SubId, Resource, Subscription_Options}
|
|
| Expired_Subscriptions];
|
|
false ->
|
|
Expired_Subscriptions
|
|
end};
|
|
_ ->
|
|
{[{Subscription_State, SubId, Resource, Subscription_Options}
|
|
| Unexpired_Subscriptions],
|
|
Expired_Subscriptions}
|
|
end);
|
|
%%
|
|
filter_expired_subscriptions(Notify_Sub, [Subscription | Subscriptions],
|
|
Offline_Resource, Online_Resources,
|
|
{Unexpired_Subscriptions, Expired_Subscriptions}) ->
|
|
filter_expired_subscriptions(Notify_Sub, Subscriptions, Offline_Resource,
|
|
Online_Resources,
|
|
{[Subscription | Unexpired_Subscriptions], Expired_Subscriptions}).
|
|
|
|
|
|
%%
|
|
roster_process_item(Roster_Item, Server) ->
|
|
spawn(pubsub_groups, monitor_roster_groups, [Server, Roster_Item]),
|
|
Roster_Item.
|
|
|
|
|
|
|
|
roster_in_subscription(Boolean, User, Server, Jid_Contact,
|
|
'subscribed' = _Subscription_Type) ->
|
|
spawn(pubsub_groups, monitor_contacts2,
|
|
['subscribed', {User, Server, undefined}, Jid_Contact]),
|
|
Boolean;
|
|
roster_in_subscription(Boolean, _User, _Server, _JID, _SubscriptionType) ->
|
|
Boolean.
|