diff options
author | Christophe Romain <christophe.romain@process-one.net> | 2012-09-11 15:45:59 +0200 |
---|---|---|
committer | Christophe Romain <christophe.romain@process-one.net> | 2012-09-11 15:45:59 +0200 |
commit | 011535f0de1a14d6f5f411035bff9eeafec1c612 (patch) | |
tree | e60951904fbdc14dc126450c4d7515f51188d4b7 /src/mod_pubsub_ng/pubsub_hooks.erl | |
parent | Merge branch '2.1.x' into 2.2.x (diff) |
binary refactoring
Diffstat (limited to 'src/mod_pubsub_ng/pubsub_hooks.erl')
-rw-r--r-- | src/mod_pubsub_ng/pubsub_hooks.erl | 570 |
1 files changed, 570 insertions, 0 deletions
diff --git a/src/mod_pubsub_ng/pubsub_hooks.erl b/src/mod_pubsub_ng/pubsub_hooks.erl new file mode 100644 index 000000000..c5c1fc28a --- /dev/null +++ b/src/mod_pubsub_ng/pubsub_hooks.erl @@ -0,0 +1,570 @@ +%%% ==================================================================== +%%% ``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-2011, ProcessOne +%%% All Rights Reserved.'' +%%% This software is copyright 2006-2011, ProcessOne. +%%% +%%% @copyright 2006-2011 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. |