mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
PubSub improvements, and solves (EJAB-453) (EJAB-608)
SVN Revision: 1408
This commit is contained in:
parent
2ccf410a75
commit
35d25d3420
32
ChangeLog
32
ChangeLog
@ -1,3 +1,35 @@
|
|||||||
|
2008-07-03 Christophe Romain <christophe.romain@process-one.net>
|
||||||
|
|
||||||
|
* src/mod_pubsub/mod_pubsub.erl: Fix permission control on item
|
||||||
|
retrieve (EJAB-453)
|
||||||
|
* src/mod_pubsub/node_dispatch.erl: Likewise
|
||||||
|
* src/mod_pubsub/node_buddy.erl: Likewise
|
||||||
|
* src/mod_pubsub/node_private.erl: Likewise
|
||||||
|
* src/mod_pubsub/node_public.erl: Likewise
|
||||||
|
* src/mod_pubsub/node_default.erl: Likewise
|
||||||
|
* src/mod_pubsub/node_pep.erl: Likewise
|
||||||
|
* src/mod_pubsub/node_club.erl: Likewise
|
||||||
|
* src/mod_pubsub/gen_pubsub_node.erl: Likewise
|
||||||
|
* src/mod_pubsub/node.template: Likewise
|
||||||
|
|
||||||
|
* src/mod_pubsub/mod_pubsub.erl: Allow subscriber to request specific
|
||||||
|
items by ItemID; Allow to retrieve pubsub#title configuration (thanks
|
||||||
|
to Kevin Crosbie); Fix forbidden result on setting
|
||||||
|
affiliation/subscription
|
||||||
|
|
||||||
|
* src/mod_pubsub/node_zoo.erl: Add node type without
|
||||||
|
home/<host>/<user> constraint
|
||||||
|
|
||||||
|
* src/ejabberd_local.erl: prevent iq_response table overload
|
||||||
|
(EJAB-608)
|
||||||
|
* src/mod_caps.erl: Likewise
|
||||||
|
|
||||||
|
* src/web/ejabberd_http.erl: Retrieve correct IP from http connection
|
||||||
|
* src/web/ejabberd_http_poll.erl: Likewise
|
||||||
|
* src/ejabberd_receiver.erl: Likewise
|
||||||
|
* src/ejabberd_sm.erl: Likewise
|
||||||
|
* src/ejabberd_c2s.erl: Likewise
|
||||||
|
|
||||||
2008-06-29 Badlop <badlop@process-one.net>
|
2008-06-29 Badlop <badlop@process-one.net>
|
||||||
|
|
||||||
* src/ejabberd_ctl.erl: Web Admin and Ad-hoc admin: dump only
|
* src/ejabberd_ctl.erl: Web Admin and Ad-hoc admin: dump only
|
||||||
|
@ -1267,6 +1267,9 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
|
|||||||
handle_info({'DOWN', Monitor, _Type, _Object, _Info}, _StateName, StateData)
|
handle_info({'DOWN', Monitor, _Type, _Object, _Info}, _StateName, StateData)
|
||||||
when Monitor == StateData#state.socket_monitor ->
|
when Monitor == StateData#state.socket_monitor ->
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
|
handle_info({peername, IP}, StateName, StateData) ->
|
||||||
|
ejabberd_sm:set_session_ip(StateData#state.sid, IP),
|
||||||
|
fsm_next_state(StateName, StateData#state{ip = IP});
|
||||||
handle_info(Info, StateName, StateData) ->
|
handle_info(Info, StateName, StateData) ->
|
||||||
?ERROR_MSG("Unexpected info: ~p", [Info]),
|
?ERROR_MSG("Unexpected info: ~p", [Info]),
|
||||||
fsm_next_state(StateName, StateData).
|
fsm_next_state(StateName, StateData).
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
register_iq_handler/5,
|
register_iq_handler/5,
|
||||||
register_iq_response_handler/4,
|
register_iq_response_handler/4,
|
||||||
unregister_iq_handler/2,
|
unregister_iq_handler/2,
|
||||||
|
unregister_iq_response_handler/2,
|
||||||
refresh_iq_handlers/0,
|
refresh_iq_handlers/0,
|
||||||
bounce_resource_packet/3
|
bounce_resource_packet/3
|
||||||
]).
|
]).
|
||||||
@ -138,6 +139,9 @@ register_iq_handler(Host, XMLNS, Module, Fun) ->
|
|||||||
register_iq_handler(Host, XMLNS, Module, Fun, Opts) ->
|
register_iq_handler(Host, XMLNS, Module, Fun, Opts) ->
|
||||||
ejabberd_local ! {register_iq_handler, Host, XMLNS, Module, Fun, Opts}.
|
ejabberd_local ! {register_iq_handler, Host, XMLNS, Module, Fun, Opts}.
|
||||||
|
|
||||||
|
unregister_iq_response_handler(Host, ID) ->
|
||||||
|
ejabberd_local ! {unregister_iq_response_handler, Host, ID}.
|
||||||
|
|
||||||
unregister_iq_handler(Host, XMLNS) ->
|
unregister_iq_handler(Host, XMLNS) ->
|
||||||
ejabberd_local ! {unregister_iq_handler, Host, XMLNS}.
|
ejabberd_local ! {unregister_iq_handler, Host, XMLNS}.
|
||||||
|
|
||||||
@ -214,6 +218,9 @@ handle_info({route, From, To, Packet}, State) ->
|
|||||||
handle_info({register_iq_response_handler, _Host, ID, Module, Function}, State) ->
|
handle_info({register_iq_response_handler, _Host, ID, Module, Function}, State) ->
|
||||||
mnesia:dirty_write(#iq_response{id = ID, module = Module, function = Function}),
|
mnesia:dirty_write(#iq_response{id = ID, module = Module, function = Function}),
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
|
handle_info({unregister_iq_response_handler, _Host, ID}, State) ->
|
||||||
|
mnesia:dirty_delete({iq_response, ID}),
|
||||||
|
{noreply, State};
|
||||||
handle_info({register_iq_handler, Host, XMLNS, Module, Function}, State) ->
|
handle_info({register_iq_handler, Host, XMLNS, Module, Function}, State) ->
|
||||||
ets:insert(?IQTABLE, {{XMLNS, Host}, Module, Function}),
|
ets:insert(?IQTABLE, {{XMLNS, Host}, Module, Function}),
|
||||||
catch mod_disco:register_feature(Host, XMLNS),
|
catch mod_disco:register_feature(Host, XMLNS),
|
||||||
|
@ -269,7 +269,8 @@ code_change(_OldVsn, State, _Extra) ->
|
|||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
activate_socket(#state{socket = Socket,
|
activate_socket(#state{socket = Socket,
|
||||||
sock_mod = SockMod}) ->
|
sock_mod = SockMod,
|
||||||
|
c2s_pid = C2SPid}) ->
|
||||||
PeerName =
|
PeerName =
|
||||||
case SockMod of
|
case SockMod of
|
||||||
gen_tcp ->
|
gen_tcp ->
|
||||||
@ -282,7 +283,8 @@ activate_socket(#state{socket = Socket,
|
|||||||
case PeerName of
|
case PeerName of
|
||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
self() ! {tcp_closed, Socket};
|
self() ! {tcp_closed, Socket};
|
||||||
{ok, _} ->
|
{ok, IP} ->
|
||||||
|
C2SPid ! {peername, IP},
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -49,7 +49,8 @@
|
|||||||
ctl_process/2,
|
ctl_process/2,
|
||||||
get_session_pid/3,
|
get_session_pid/3,
|
||||||
get_user_info/3,
|
get_user_info/3,
|
||||||
get_user_ip/3
|
get_user_ip/3,
|
||||||
|
set_session_ip/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
@ -164,6 +165,18 @@ get_user_info(User, Server, Resource) ->
|
|||||||
[{node, Node}, {conn, Conn}, {ip, IP}]
|
[{node, Node}, {conn, Conn}, {ip, IP}]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
set_session_ip(SID, IP) ->
|
||||||
|
case mnesia:dirty_read(session, SID) of
|
||||||
|
[#session{info = Info} = Session] ->
|
||||||
|
NewInfo = case lists:keymember(ip, 1, Info) of
|
||||||
|
true -> lists:keyreplace(ip, 1, Info, {ip, IP});
|
||||||
|
false -> [{ip, IP}|Info]
|
||||||
|
end,
|
||||||
|
mnesia:dirty_write(Session#session{info = NewInfo});
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
set_presence(SID, User, Server, Resource, Priority, Presence, Info) ->
|
set_presence(SID, User, Server, Resource, Priority, Presence, Info) ->
|
||||||
set_session(SID, User, Server, Resource, Priority, Info),
|
set_session(SID, User, Server, Resource, Priority, Info),
|
||||||
ejabberd_hooks:run(set_presence_hook, jlib:nameprep(Server),
|
ejabberd_hooks:run(set_presence_hook, jlib:nameprep(Server),
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
|
|
||||||
-define(PROCNAME, ejabberd_mod_caps).
|
-define(PROCNAME, ejabberd_mod_caps).
|
||||||
-define(DICT, dict).
|
-define(DICT, dict).
|
||||||
|
-define(CAPS_QUERY_TIMEOUT, 60000). % 1mn without answer, consider client never answer
|
||||||
|
|
||||||
-record(caps, {node, version, exts}).
|
-record(caps, {node, version, exts}).
|
||||||
-record(caps_features, {node_pair, features}).
|
-record(caps_features, {node_pair, features}).
|
||||||
@ -220,6 +221,7 @@ handle_cast({note_caps, From,
|
|||||||
ejabberd_local:register_iq_response_handler
|
ejabberd_local:register_iq_response_handler
|
||||||
(Host, ID, ?MODULE, handle_disco_response),
|
(Host, ID, ?MODULE, handle_disco_response),
|
||||||
ejabberd_router:route(jlib:make_jid("", Host, ""), From, Stanza),
|
ejabberd_router:route(jlib:make_jid("", Host, ""), From, Stanza),
|
||||||
|
timer:send_after(?CAPS_QUERY_TIMEOUT, self(), {disco_timeout, ID}),
|
||||||
?DICT:store(ID, {Node, SubNode}, Dict)
|
?DICT:store(ID, {Node, SubNode}, Dict)
|
||||||
end, Requests, Missing),
|
end, Requests, Missing),
|
||||||
{noreply, State#state{disco_requests = NewRequests}};
|
{noreply, State#state{disco_requests = NewRequests}};
|
||||||
@ -274,6 +276,16 @@ handle_cast({disco_response, From, _To,
|
|||||||
end,
|
end,
|
||||||
NewRequests = ?DICT:erase(ID, Requests),
|
NewRequests = ?DICT:erase(ID, Requests),
|
||||||
{noreply, State#state{disco_requests = NewRequests}};
|
{noreply, State#state{disco_requests = NewRequests}};
|
||||||
|
handle_cast({disco_timeout, ID}, #state{host = Host, disco_requests = Requests} = State) ->
|
||||||
|
%% do not wait a response anymore for this IQ, client certainly will never answer
|
||||||
|
NewRequests = case ?DICT:is_key(ID, Requests) of
|
||||||
|
true ->
|
||||||
|
ejabberd_local:unregister_iq_response_handler(Host, ID),
|
||||||
|
?DICT:erase(ID, Requests);
|
||||||
|
false ->
|
||||||
|
Requests
|
||||||
|
end,
|
||||||
|
{noreply, State#state{disco_requests = NewRequests}};
|
||||||
handle_cast(visit_feature_queries, #state{feature_queries = FeatureQueries} = State) ->
|
handle_cast(visit_feature_queries, #state{feature_queries = FeatureQueries} = State) ->
|
||||||
Timestamp = timestamp(),
|
Timestamp = timestamp(),
|
||||||
NewFeatureQueries =
|
NewFeatureQueries =
|
||||||
|
@ -62,7 +62,9 @@ behaviour_info(callbacks) ->
|
|||||||
{get_states, 2},
|
{get_states, 2},
|
||||||
{get_state, 3},
|
{get_state, 3},
|
||||||
{set_state, 1},
|
{set_state, 1},
|
||||||
|
{get_items, 7},
|
||||||
{get_items, 2},
|
{get_items, 2},
|
||||||
|
{get_item, 8},
|
||||||
{get_item, 3},
|
{get_item, 3},
|
||||||
{set_item, 1},
|
{set_item, 1},
|
||||||
{get_item_name, 3}
|
{get_item_name, 3}
|
||||||
|
@ -30,16 +30,17 @@
|
|||||||
%%%
|
%%%
|
||||||
%%% @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.10 of the specification as a base.
|
%%% This module uses version 1.11 of the specification as a base.
|
||||||
%%% Most of the specification is implemented.
|
%%% Most of the specification is implemented.
|
||||||
%%% Code is derivated from the original pubsub v1.7, functions concerning config may be rewritten.
|
%%% Functions concerning configuration should be rewritten.
|
||||||
%%% Code also inspired from the original PEP patch by Magnus Henoch (mangeATfreemail.hu)
|
%%% Code is derivated from the original pubsub v1.7, by Alexey Shchepin <alexey@process-one.net>
|
||||||
|
|
||||||
%%% TODO
|
%%% TODO
|
||||||
%%% plugin: generate Reply (do not use broadcast atom anymore)
|
%%% plugin: generate Reply (do not use broadcast atom anymore)
|
||||||
|
|
||||||
-module(mod_pubsub).
|
-module(mod_pubsub).
|
||||||
-version('1.10-01').
|
-author('christophe.romain@process-one.net').
|
||||||
|
-version('1.11-01').
|
||||||
|
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
-behaviour(gen_mod).
|
-behaviour(gen_mod).
|
||||||
@ -912,7 +913,17 @@ iq_pubsub(Host, ServerHost, From, IQType, SubEl, _Lang, Access, Plugins) ->
|
|||||||
unsubscribe_node(Host, Node, From, JID, SubId);
|
unsubscribe_node(Host, Node, From, JID, SubId);
|
||||||
{get, "items"} ->
|
{get, "items"} ->
|
||||||
MaxItems = xml:get_attr_s("max_items", Attrs),
|
MaxItems = xml:get_attr_s("max_items", Attrs),
|
||||||
get_items(Host, Node, From, MaxItems);
|
SubId = xml:get_attr_s("subid", Attrs),
|
||||||
|
ItemIDs = lists:foldl(fun
|
||||||
|
({xmlelement, "item", ItemAttrs, _}, Acc) ->
|
||||||
|
case xml:get_attr_s("id", ItemAttrs) of
|
||||||
|
"" -> Acc;
|
||||||
|
ItemID -> ItemID
|
||||||
|
end;
|
||||||
|
(_, Acc) ->
|
||||||
|
Acc
|
||||||
|
end, [], xml:remove_cdata(Els)),
|
||||||
|
get_items(Host, Node, From, SubId, MaxItems, ItemIDs);
|
||||||
{get, "subscriptions"} ->
|
{get, "subscriptions"} ->
|
||||||
get_subscriptions(Host, From, Plugins);
|
get_subscriptions(Host, From, Plugins);
|
||||||
{get, "affiliations"} ->
|
{get, "affiliations"} ->
|
||||||
@ -1436,7 +1447,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
|
|||||||
Action = fun(#pubsub_node{options = Options, type = Type}) ->
|
Action = fun(#pubsub_node{options = Options, type = Type}) ->
|
||||||
Features = features(Type),
|
Features = features(Type),
|
||||||
PublishFeature = lists:member("publish", Features),
|
PublishFeature = lists:member("publish", Features),
|
||||||
Model = get_option(Options, publish_model),
|
PublishModel = get_option(Options, publish_model),
|
||||||
MaxItems = max_items(Options),
|
MaxItems = max_items(Options),
|
||||||
PayloadSize = size(term_to_binary(Payload)),
|
PayloadSize = size(term_to_binary(Payload)),
|
||||||
PayloadMaxSize = get_option(Options, max_payload_size),
|
PayloadMaxSize = get_option(Options, max_payload_size),
|
||||||
@ -1459,7 +1470,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
|
|||||||
%% % Publisher attempts to publish to transient notification node with item
|
%% % Publisher attempts to publish to transient notification node with item
|
||||||
%% {error, extended_error(?ERR_BAD_REQUEST, "item-forbidden")};
|
%% {error, extended_error(?ERR_BAD_REQUEST, "item-forbidden")};
|
||||||
true ->
|
true ->
|
||||||
node_call(Type, publish_item, [Host, Node, Publisher, Model, MaxItems, ItemId, Payload])
|
node_call(Type, publish_item, [Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload])
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
%%ejabberd_hooks:run(pubsub_publish_item, Host, [Host, Node, JID, service_jid(Host), ItemId, Payload]),
|
%%ejabberd_hooks:run(pubsub_publish_item, Host, [Host, Node, JID, service_jid(Host), ItemId, Payload]),
|
||||||
@ -1622,7 +1633,7 @@ purge_node(Host, Node, Owner) ->
|
|||||||
%% <p>The permission are not checked in this function.</p>
|
%% <p>The permission are not checked in this function.</p>
|
||||||
%% @todo We probably need to check that the user doing the query has the right
|
%% @todo We probably need to check that the user doing the query has the right
|
||||||
%% to read the items.
|
%% to read the items.
|
||||||
get_items(Host, Node, _JID, SMaxItems) ->
|
get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) ->
|
||||||
MaxItems =
|
MaxItems =
|
||||||
if
|
if
|
||||||
SMaxItems == "" -> ?MAXITEMS;
|
SMaxItems == "" -> ?MAXITEMS;
|
||||||
@ -1636,10 +1647,46 @@ get_items(Host, Node, _JID, SMaxItems) ->
|
|||||||
{error, Error} ->
|
{error, Error} ->
|
||||||
{error, Error};
|
{error, Error};
|
||||||
_ ->
|
_ ->
|
||||||
case get_items(Host, Node) of
|
Action = fun(#pubsub_node{options = Options, type = Type}) ->
|
||||||
|
Features = features(Type),
|
||||||
|
RetreiveFeature = lists:member("retrieve-items", Features),
|
||||||
|
PersistentFeature = lists:member("persistent-items", Features),
|
||||||
|
AccessModel = get_option(Options, access_model),
|
||||||
|
AllowedGroups = get_option(Options, roster_groups_allowed),
|
||||||
|
{PresenceSubscription, RosterGroup} =
|
||||||
|
case Host of
|
||||||
|
{OUser, OServer, _} ->
|
||||||
|
get_roster_info(OUser, OServer,
|
||||||
|
jlib:jid_tolower(From), AllowedGroups);
|
||||||
|
_ ->
|
||||||
|
{true, true}
|
||||||
|
end,
|
||||||
|
if
|
||||||
|
not RetreiveFeature ->
|
||||||
|
%% Item Retrieval Not Supported
|
||||||
|
{error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "retrieve-items")};
|
||||||
|
not PersistentFeature ->
|
||||||
|
%% Persistent Items Not Supported
|
||||||
|
{error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "persistent-items")};
|
||||||
|
true ->
|
||||||
|
node_call(Type, get_items,
|
||||||
|
[Host, Node, From,
|
||||||
|
AccessModel, PresenceSubscription, RosterGroup,
|
||||||
|
SubId])
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
case transaction(Host, Node, Action, sync_dirty) of
|
||||||
|
{error, Reason} ->
|
||||||
|
{error, Reason};
|
||||||
|
{result, Items} ->
|
||||||
|
SendItems = case ItemIDs of
|
||||||
[] ->
|
[] ->
|
||||||
{error, ?ERR_ITEM_NOT_FOUND};
|
Items;
|
||||||
Items ->
|
_ ->
|
||||||
|
lists:filter(fun(Item) ->
|
||||||
|
lists:member(Item, ItemIDs)
|
||||||
|
end, Items)
|
||||||
|
end,
|
||||||
%% Generate the XML response (Item list), limiting the
|
%% Generate the XML response (Item list), limiting the
|
||||||
%% number of items sent to MaxItems:
|
%% number of items sent to MaxItems:
|
||||||
ItemsEls = lists:map(
|
ItemsEls = lists:map(
|
||||||
@ -1650,7 +1697,7 @@ get_items(Host, Node, _JID, SMaxItems) ->
|
|||||||
_ -> [{"id", ItemId}]
|
_ -> [{"id", ItemId}]
|
||||||
end,
|
end,
|
||||||
{xmlelement, "item", ItemAttrs, Payload}
|
{xmlelement, "item", ItemAttrs, Payload}
|
||||||
end, lists:sublist(Items, MaxItems)),
|
end, lists:sublist(SendItems, MaxItems)),
|
||||||
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
|
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
|
||||||
[{xmlelement, "items", [{"node", node_to_string(Node)}],
|
[{xmlelement, "items", [{"node", node_to_string(Node)}],
|
||||||
ItemsEls}]}]}
|
ItemsEls}]}]}
|
||||||
@ -1809,7 +1856,7 @@ set_affiliations(Host, Node, From, EntitiesEls) ->
|
|||||||
end, Entities),
|
end, Entities),
|
||||||
{result, []};
|
{result, []};
|
||||||
_ ->
|
_ ->
|
||||||
{error, ?ERR_NOT_ALLOWED}
|
{error, ?ERR_FORBIDDEN}
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
transaction(Host, Node, Action, sync_dirty)
|
transaction(Host, Node, Action, sync_dirty)
|
||||||
@ -1870,7 +1917,7 @@ get_subscriptions(Host, Node, JID) ->
|
|||||||
%% Service does not support manage subscriptions
|
%% Service does not support manage subscriptions
|
||||||
{error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "manage-affiliations")};
|
{error, extended_error(?ERR_FEATURE_NOT_IMPLEMENTED, unsupported, "manage-affiliations")};
|
||||||
Affiliation /= {result, owner} ->
|
Affiliation /= {result, owner} ->
|
||||||
% Entity is not an owner
|
%% Entity is not an owner
|
||||||
{error, ?ERR_FORBIDDEN};
|
{error, ?ERR_FORBIDDEN};
|
||||||
true ->
|
true ->
|
||||||
node_call(Type, get_node_subscriptions, [Host, Node])
|
node_call(Type, get_node_subscriptions, [Host, Node])
|
||||||
@ -1938,7 +1985,7 @@ set_subscriptions(Host, Node, From, EntitiesEls) ->
|
|||||||
end, Entities),
|
end, Entities),
|
||||||
{result, []};
|
{result, []};
|
||||||
_ ->
|
_ ->
|
||||||
{error, ?ERR_NOT_ALLOWED}
|
{error, ?ERR_FORBIDDEN}
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
transaction(Host, Node, Action, sync_dirty)
|
transaction(Host, Node, Action, sync_dirty)
|
||||||
@ -2438,6 +2485,7 @@ get_configure_xfields(_Type, Options, Lang, _Owners) ->
|
|||||||
?BOOL_CONFIG_FIELD("Notify subscribers when the node is deleted", notify_delete),
|
?BOOL_CONFIG_FIELD("Notify subscribers when the node is deleted", notify_delete),
|
||||||
?BOOL_CONFIG_FIELD("Notify subscribers when items are removed from the node", notify_retract),
|
?BOOL_CONFIG_FIELD("Notify subscribers when items are removed from the node", notify_retract),
|
||||||
?BOOL_CONFIG_FIELD("Persist items to storage", persist_items),
|
?BOOL_CONFIG_FIELD("Persist items to storage", persist_items),
|
||||||
|
?STRING_CONFIG_FIELD("A friendly name for the node", title),
|
||||||
?INTEGER_CONFIG_FIELD("Max # of items to persist", max_items),
|
?INTEGER_CONFIG_FIELD("Max # of items to persist", max_items),
|
||||||
?BOOL_CONFIG_FIELD("Whether to allow subscriptions", subscribe),
|
?BOOL_CONFIG_FIELD("Whether to allow subscriptions", subscribe),
|
||||||
?ALIST_CONFIG_FIELD("Specify the access model", access_model,
|
?ALIST_CONFIG_FIELD("Specify the access model", access_model,
|
||||||
@ -2605,7 +2653,7 @@ features() ->
|
|||||||
[
|
[
|
||||||
%"access-authorize", % OPTIONAL
|
%"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
|
"access-presence", % OPTIONAL this relates to access_model option in node_pep
|
||||||
%"access-roster", % OPTIONAL
|
%"access-roster", % OPTIONAL
|
||||||
%"access-whitelist", % OPTIONAL
|
%"access-whitelist", % OPTIONAL
|
||||||
% see plugin "auto-create", % OPTIONAL
|
% see plugin "auto-create", % OPTIONAL
|
||||||
@ -2619,7 +2667,7 @@ features() ->
|
|||||||
% see plugin "filtered-notifications", % RECOMMENDED
|
% see plugin "filtered-notifications", % RECOMMENDED
|
||||||
%TODO "get-pending", % OPTIONAL
|
%TODO "get-pending", % OPTIONAL
|
||||||
% see plugin "instant-nodes", % RECOMMENDED
|
% see plugin "instant-nodes", % RECOMMENDED
|
||||||
%TODO "item-ids", % RECOMMENDED
|
"item-ids", % RECOMMENDED
|
||||||
"last-published", % RECOMMENDED
|
"last-published", % RECOMMENDED
|
||||||
%TODO "cache-last-item",
|
%TODO "cache-last-item",
|
||||||
%TODO "leased-subscription", % OPTIONAL
|
%TODO "leased-subscription", % OPTIONAL
|
||||||
|
@ -61,7 +61,9 @@
|
|||||||
get_states/2,
|
get_states/2,
|
||||||
get_state/3,
|
get_state/3,
|
||||||
set_state/1,
|
set_state/1,
|
||||||
|
get_items/7,
|
||||||
get_items/2,
|
get_items/2,
|
||||||
|
get_item/8,
|
||||||
get_item/3,
|
get_item/3,
|
||||||
set_item/1
|
set_item/1
|
||||||
]).
|
]).
|
||||||
@ -94,7 +96,6 @@ features() ->
|
|||||||
["create-nodes",
|
["create-nodes",
|
||||||
"delete-nodes",
|
"delete-nodes",
|
||||||
"instant-nodes",
|
"instant-nodes",
|
||||||
"item-ids",
|
|
||||||
"outcast-affiliation",
|
"outcast-affiliation",
|
||||||
"persistent-items",
|
"persistent-items",
|
||||||
"publish",
|
"publish",
|
||||||
@ -170,8 +171,14 @@ set_state(State) ->
|
|||||||
get_items(Host, Node) ->
|
get_items(Host, Node) ->
|
||||||
node_default:get_items(Host, Node).
|
node_default:get_items(Host, Node).
|
||||||
|
|
||||||
|
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId)
|
||||||
|
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
get_item(Host, Node, ItemId) ->
|
get_item(Host, Node, ItemId) ->
|
||||||
node_default:get_item(Host, Node, ItemId).
|
node_default:get_item(Host, Node, ItemId).
|
||||||
|
|
||||||
|
get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
set_item(Item) ->
|
set_item(Item) ->
|
||||||
node_default:set_item(Item).
|
node_default:set_item(Item).
|
||||||
|
@ -62,7 +62,9 @@
|
|||||||
get_states/2,
|
get_states/2,
|
||||||
get_state/3,
|
get_state/3,
|
||||||
set_state/1,
|
set_state/1,
|
||||||
|
get_items/7,
|
||||||
get_items/2,
|
get_items/2,
|
||||||
|
get_item/8,
|
||||||
get_item/3,
|
get_item/3,
|
||||||
set_item/1,
|
set_item/1,
|
||||||
get_item_name/3
|
get_item_name/3
|
||||||
@ -172,9 +174,15 @@ set_state(State) ->
|
|||||||
get_items(Host, Node) ->
|
get_items(Host, Node) ->
|
||||||
node_default:get_items(Host, Node).
|
node_default:get_items(Host, Node).
|
||||||
|
|
||||||
|
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
get_item(Host, Node, ItemId) ->
|
get_item(Host, Node, ItemId) ->
|
||||||
node_default:get_item(Host, Node, ItemId).
|
node_default:get_item(Host, Node, ItemId).
|
||||||
|
|
||||||
|
get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
set_item(Item) ->
|
set_item(Item) ->
|
||||||
node_default:set_item(Item).
|
node_default:set_item(Item).
|
||||||
|
|
||||||
|
@ -62,7 +62,9 @@
|
|||||||
get_states/2,
|
get_states/2,
|
||||||
get_state/3,
|
get_state/3,
|
||||||
set_state/1,
|
set_state/1,
|
||||||
|
get_items/7,
|
||||||
get_items/2,
|
get_items/2,
|
||||||
|
get_item/8,
|
||||||
get_item/3,
|
get_item/3,
|
||||||
set_item/1,
|
set_item/1,
|
||||||
get_item_name/3
|
get_item_name/3
|
||||||
@ -96,7 +98,6 @@ features() ->
|
|||||||
["create-nodes",
|
["create-nodes",
|
||||||
"delete-nodes",
|
"delete-nodes",
|
||||||
"instant-nodes",
|
"instant-nodes",
|
||||||
"item-ids",
|
|
||||||
"outcast-affiliation",
|
"outcast-affiliation",
|
||||||
"persistent-items",
|
"persistent-items",
|
||||||
"publish",
|
"publish",
|
||||||
@ -172,9 +173,15 @@ set_state(State) ->
|
|||||||
get_items(Host, Node) ->
|
get_items(Host, Node) ->
|
||||||
node_default:get_items(Host, Node).
|
node_default:get_items(Host, Node).
|
||||||
|
|
||||||
|
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
get_item(Host, Node, ItemId) ->
|
get_item(Host, Node, ItemId) ->
|
||||||
node_default:get_item(Host, Node, ItemId).
|
node_default:get_item(Host, Node, ItemId).
|
||||||
|
|
||||||
|
get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
set_item(Item) ->
|
set_item(Item) ->
|
||||||
node_default:set_item(Item).
|
node_default:set_item(Item).
|
||||||
|
|
||||||
|
@ -69,7 +69,9 @@
|
|||||||
get_states/2,
|
get_states/2,
|
||||||
get_state/3,
|
get_state/3,
|
||||||
set_state/1,
|
set_state/1,
|
||||||
|
get_items/7,
|
||||||
get_items/2,
|
get_items/2,
|
||||||
|
get_item/8,
|
||||||
get_item/3,
|
get_item/3,
|
||||||
set_item/1,
|
set_item/1,
|
||||||
get_item_name/3
|
get_item_name/3
|
||||||
@ -158,7 +160,6 @@ features() ->
|
|||||||
"auto-create",
|
"auto-create",
|
||||||
"delete-nodes",
|
"delete-nodes",
|
||||||
"instant-nodes",
|
"instant-nodes",
|
||||||
"item-ids",
|
|
||||||
"manage-subscriptions",
|
"manage-subscriptions",
|
||||||
"modify-affiliations",
|
"modify-affiliations",
|
||||||
"outcast-affiliation",
|
"outcast-affiliation",
|
||||||
@ -192,18 +193,14 @@ features() ->
|
|||||||
%% module by implementing this function like this:
|
%% module by implementing this function like this:
|
||||||
%% ```check_create_user_permission(Host, Node, Owner, Access) ->
|
%% ```check_create_user_permission(Host, Node, Owner, Access) ->
|
||||||
%% node_default:check_create_user_permission(Host, Node, Owner, Access).'''</p>
|
%% node_default:check_create_user_permission(Host, Node, Owner, Access).'''</p>
|
||||||
create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) ->
|
create_node_permission(_Host, ServerHost, Node, _ParentNode, Owner, Access) ->
|
||||||
LOwner = jlib:jid_tolower(Owner),
|
LOwner = jlib:jid_tolower(Owner),
|
||||||
{User, Server, _Resource} = LOwner,
|
{User, Server, _Resource} = LOwner,
|
||||||
Allowed = case acl:match_rule(ServerHost, Access, LOwner) of
|
Allowed = case acl:match_rule(ServerHost, Access, LOwner) of
|
||||||
allow ->
|
allow ->
|
||||||
if Server == Host -> %% Server == ServerHost ??
|
|
||||||
true;
|
|
||||||
true ->
|
|
||||||
case Node of
|
case Node of
|
||||||
["home", Server, User | _] -> true;
|
["home", Server, User | _] -> true;
|
||||||
_ -> false
|
_ -> false
|
||||||
end
|
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
case Owner of
|
case Owner of
|
||||||
@ -211,8 +208,7 @@ create_node_permission(Host, ServerHost, Node, _ParentNode, Owner, Access) ->
|
|||||||
_ -> false
|
_ -> false
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
ChildOK = true, %% TODO test with ParentNode
|
{result, Allowed}.
|
||||||
{result, Allowed and ChildOK}.
|
|
||||||
|
|
||||||
%% @spec (Host, Node, Owner) ->
|
%% @spec (Host, Node, Owner) ->
|
||||||
%% {result, Result} | exit
|
%% {result, Result} | exit
|
||||||
@ -297,12 +293,12 @@ subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
|
|||||||
not Authorized ->
|
not Authorized ->
|
||||||
%% JIDs do not match
|
%% JIDs do not match
|
||||||
{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "invalid-jid")};
|
{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "invalid-jid")};
|
||||||
Subscription == pending ->
|
|
||||||
%% Requesting entity has pending subscription
|
|
||||||
{error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "pending-subscription")};
|
|
||||||
Affiliation == outcast ->
|
Affiliation == outcast ->
|
||||||
%% Requesting entity is blocked
|
%% Requesting entity is blocked
|
||||||
{error, ?ERR_FORBIDDEN};
|
{error, ?ERR_FORBIDDEN};
|
||||||
|
Subscription == pending ->
|
||||||
|
%% Requesting entity has pending subscription
|
||||||
|
{error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "pending-subscription")};
|
||||||
(AccessModel == presence) and (not PresenceSubscription) ->
|
(AccessModel == presence) and (not PresenceSubscription) ->
|
||||||
%% Entity is not authorized to create a subscription (presence subscription required)
|
%% Entity is not authorized to create a subscription (presence subscription required)
|
||||||
{error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "presence-subscription-required")};
|
{error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "presence-subscription-required")};
|
||||||
@ -446,6 +442,7 @@ publish_item(Host, Node, Publisher, PublishModel, MaxItems, ItemId, Payload) ->
|
|||||||
{error, ?ERR_FORBIDDEN};
|
{error, ?ERR_FORBIDDEN};
|
||||||
true ->
|
true ->
|
||||||
PubId = {PublisherKey, now()},
|
PubId = {PublisherKey, now()},
|
||||||
|
%% 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} ->
|
{error, ?ERR_ITEM_NOT_FOUND} ->
|
||||||
#pubsub_item{itemid = {ItemId, {Host, Node}},
|
#pubsub_item{itemid = {ItemId, {Host, Node}},
|
||||||
@ -501,7 +498,7 @@ remove_extra_items(Host, Node, MaxItems, ItemIds) ->
|
|||||||
%% ItemId = string()
|
%% ItemId = string()
|
||||||
%% @doc <p>Triggers item deletion.</p>
|
%% @doc <p>Triggers item deletion.</p>
|
||||||
%% <p>Default plugin: The user performing the deletion must be the node owner
|
%% <p>Default plugin: The user performing the deletion must be the node owner
|
||||||
%% or a node publisher e item 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 = case get_state(Host, Node, PublisherKey) of
|
||||||
@ -542,17 +539,16 @@ 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
|
||||||
{error, ?ERR_ITEM_NOT_FOUND} ->
|
|
||||||
%% This should not append (case node does not exists)
|
|
||||||
{error, ?ERR_ITEM_NOT_FOUND};
|
|
||||||
{result, #pubsub_state{items = Items, affiliation = owner}} ->
|
{result, #pubsub_state{items = Items, affiliation = owner}} ->
|
||||||
lists:foreach(fun(ItemId) ->
|
lists:foreach(fun(ItemId) ->
|
||||||
mnesia:delete({pubsub_item, {ItemId, {Host, Node}}})
|
mnesia:delete({pubsub_item, {ItemId, {Host, Node}}})
|
||||||
end, Items),
|
end, Items),
|
||||||
{result, {default, broadcast}};
|
{result, {default, broadcast}};
|
||||||
|
{result, _} ->
|
||||||
|
%% Entity is not owner
|
||||||
|
{error, ?ERR_FORBIDDEN};
|
||||||
_ ->
|
_ ->
|
||||||
%% Entity is not an owner
|
{error, ?ERR_ITEM_NOT_FOUND}
|
||||||
{error, ?ERR_FORBIDDEN}
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @spec (Host, JID) -> [{Node,Affiliation}]
|
%% @spec (Host, JID) -> [{Node,Affiliation}]
|
||||||
@ -588,7 +584,7 @@ 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
|
Affiliation = case get_state(Host, Node, OwnerKey) of
|
||||||
{result, #pubsub_state{affiliation = A}} -> A;
|
{result, #pubsub_state{affiliation = A}} -> A;
|
||||||
_ -> unknown
|
_ -> none
|
||||||
end,
|
end,
|
||||||
{result, Affiliation}.
|
{result, Affiliation}.
|
||||||
|
|
||||||
@ -638,7 +634,7 @@ 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
|
Subscription = case get_state(Host, Node, OwnerKey) of
|
||||||
{result, #pubsub_state{subscription = S}} -> S;
|
{result, #pubsub_state{subscription = S}} -> S;
|
||||||
_ -> unknown
|
_ -> none
|
||||||
end,
|
end,
|
||||||
{result, Subscription}.
|
{result, Subscription}.
|
||||||
|
|
||||||
@ -713,6 +709,44 @@ get_items(Host, Node) ->
|
|||||||
Items = mnesia:match_object(
|
Items = mnesia:match_object(
|
||||||
#pubsub_item{itemid = {'_', {Host, Node}}, _ = '_'}),
|
#pubsub_item{itemid = {'_', {Host, Node}}, _ = '_'}),
|
||||||
{result, Items}.
|
{result, Items}.
|
||||||
|
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubId) ->
|
||||||
|
{Affiliation, Subscription} =
|
||||||
|
case get_state(Host, Node, jlib:jid_tolower(jlib:jid_remove_resource(JID))) of
|
||||||
|
{result, #pubsub_state{affiliation = A, subscription = S}} -> {A, S};
|
||||||
|
_ -> {none, none}
|
||||||
|
end,
|
||||||
|
Subscribed = not ((Subscription == none) or (Subscription == pending)),
|
||||||
|
if
|
||||||
|
%%SubID == "", ?? ->
|
||||||
|
%% Entity has multiple subscriptions to the node but does not specify a subscription ID
|
||||||
|
%{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")};
|
||||||
|
%%InvalidSubID ->
|
||||||
|
%% Entity is subscribed but specifies an invalid subscription ID
|
||||||
|
%{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
|
||||||
|
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")};
|
||||||
|
(AccessModel == roster) and (not RosterGroup) ->
|
||||||
|
%% Entity is not authorized to create a subscription (not in roster group)
|
||||||
|
{error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "not-in-roster-group")};
|
||||||
|
(AccessModel == whitelist) -> % TODO: to be done
|
||||||
|
%% Node has whitelist access model
|
||||||
|
{error, ?ERR_EXTENDED(?ERR_NOT_ALLOWED, "closed-node")};
|
||||||
|
(AccessModel == authorize) -> % TODO: to be done
|
||||||
|
%% Node has authorize access model
|
||||||
|
{error, ?ERR_FORBIDDEN};
|
||||||
|
%%MustPay ->
|
||||||
|
%% % Payment is required for a subscription
|
||||||
|
%% {error, ?ERR_PAYMENT_REQUIRED};
|
||||||
|
true ->
|
||||||
|
get_items(Host, Node)
|
||||||
|
end.
|
||||||
|
|
||||||
%% @spec (Host, Node, ItemId) -> [Item] | []
|
%% @spec (Host, Node, ItemId) -> [Item] | []
|
||||||
%% Host = mod_pubsub:host()
|
%% Host = mod_pubsub:host()
|
||||||
@ -727,6 +761,44 @@ 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) ->
|
||||||
|
{Affiliation, Subscription} =
|
||||||
|
case get_state(Host, Node, jlib:jid_tolower(jlib:jid_remove_resource(JID))) of
|
||||||
|
{result, #pubsub_state{affiliation = A, subscription = S}} -> {A, S};
|
||||||
|
_ -> {none, none}
|
||||||
|
end,
|
||||||
|
Subscribed = not ((Subscription == none) or (Subscription == pending)),
|
||||||
|
if
|
||||||
|
%%SubID == "", ?? ->
|
||||||
|
%% Entity has multiple subscriptions to the node but does not specify a subscription ID
|
||||||
|
%{error, ?ERR_EXTENDED(?ERR_BAD_REQUEST, "subid-required")};
|
||||||
|
%%InvalidSubID ->
|
||||||
|
%% Entity is subscribed but specifies an invalid subscription ID
|
||||||
|
%{error, ?ERR_EXTENDED(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
|
||||||
|
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")};
|
||||||
|
(AccessModel == roster) and (not RosterGroup) ->
|
||||||
|
%% Entity is not authorized to create a subscription (not in roster group)
|
||||||
|
{error, ?ERR_EXTENDED(?ERR_NOT_AUTHORIZED, "not-in-roster-group")};
|
||||||
|
(AccessModel == whitelist) -> % TODO: to be done
|
||||||
|
%% Node has whitelist access model
|
||||||
|
{error, ?ERR_EXTENDED(?ERR_NOT_ALLOWED, "closed-node")};
|
||||||
|
(AccessModel == authorize) -> % TODO: to be done
|
||||||
|
%% Node has authorize access model
|
||||||
|
{error, ?ERR_FORBIDDEN};
|
||||||
|
%%MustPay ->
|
||||||
|
%% % Payment is required for a subscription
|
||||||
|
%% {error, ?ERR_PAYMENT_REQUIRED};
|
||||||
|
true ->
|
||||||
|
get_item(Host, Node, ItemId)
|
||||||
|
end.
|
||||||
|
|
||||||
%% @spec (Item) -> ok | {error, Reason::stanzaError()}
|
%% @spec (Item) -> ok | {error, Reason::stanzaError()}
|
||||||
%% Item = mod_pubsub:pubsubItems()
|
%% Item = mod_pubsub:pubsubItems()
|
||||||
|
@ -60,7 +60,9 @@
|
|||||||
get_states/2,
|
get_states/2,
|
||||||
get_state/3,
|
get_state/3,
|
||||||
set_state/1,
|
set_state/1,
|
||||||
|
get_items/7,
|
||||||
get_items/2,
|
get_items/2,
|
||||||
|
get_item/8,
|
||||||
get_item/3,
|
get_item/3,
|
||||||
set_item/1,
|
set_item/1,
|
||||||
get_item_name/3
|
get_item_name/3
|
||||||
@ -94,7 +96,6 @@ features() ->
|
|||||||
["create-nodes",
|
["create-nodes",
|
||||||
"delete-nodes",
|
"delete-nodes",
|
||||||
"instant-nodes",
|
"instant-nodes",
|
||||||
"item-ids",
|
|
||||||
"outcast-affiliation",
|
"outcast-affiliation",
|
||||||
"persistent-items",
|
"persistent-items",
|
||||||
"publish",
|
"publish",
|
||||||
@ -175,9 +176,15 @@ set_state(State) ->
|
|||||||
get_items(Host, Node) ->
|
get_items(Host, Node) ->
|
||||||
node_default:get_items(Host, Node).
|
node_default:get_items(Host, Node).
|
||||||
|
|
||||||
|
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
get_item(Host, Node, ItemId) ->
|
get_item(Host, Node, ItemId) ->
|
||||||
node_default:get_item(Host, Node, ItemId).
|
node_default:get_item(Host, Node, ItemId).
|
||||||
|
|
||||||
|
get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
set_item(Item) ->
|
set_item(Item) ->
|
||||||
node_default:set_item(Item).
|
node_default:set_item(Item).
|
||||||
|
|
||||||
|
@ -58,7 +58,9 @@
|
|||||||
get_states/2,
|
get_states/2,
|
||||||
get_state/3,
|
get_state/3,
|
||||||
set_state/1,
|
set_state/1,
|
||||||
|
get_items/7,
|
||||||
get_items/2,
|
get_items/2,
|
||||||
|
get_item/8,
|
||||||
get_item/3,
|
get_item/3,
|
||||||
set_item/1,
|
set_item/1,
|
||||||
get_item_name/3
|
get_item_name/3
|
||||||
@ -96,7 +98,6 @@ features() ->
|
|||||||
"auto-subscribe", %*
|
"auto-subscribe", %*
|
||||||
"delete-nodes", %*
|
"delete-nodes", %*
|
||||||
"filtered-notifications", %*
|
"filtered-notifications", %*
|
||||||
"item-ids",
|
|
||||||
"modify-affiliations",
|
"modify-affiliations",
|
||||||
"outcast-affiliation",
|
"outcast-affiliation",
|
||||||
"persistent-items",
|
"persistent-items",
|
||||||
@ -185,7 +186,7 @@ get_node_subscriptions(_Host, _Node) ->
|
|||||||
{result, []}.
|
{result, []}.
|
||||||
|
|
||||||
get_subscription(_Host, _Node, _Owner) ->
|
get_subscription(_Host, _Node, _Owner) ->
|
||||||
{result, unknown}.
|
{result, none}.
|
||||||
|
|
||||||
set_subscription(_Host, _Node, _Owner, _Subscription) ->
|
set_subscription(_Host, _Node, _Owner, _Subscription) ->
|
||||||
ok.
|
ok.
|
||||||
@ -202,9 +203,15 @@ set_state(State) ->
|
|||||||
get_items(Host, Node) ->
|
get_items(Host, Node) ->
|
||||||
node_default:get_items(Host, Node).
|
node_default:get_items(Host, Node).
|
||||||
|
|
||||||
|
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
get_item(Host, Node, ItemId) ->
|
get_item(Host, Node, ItemId) ->
|
||||||
node_default:get_item(Host, Node, ItemId).
|
node_default:get_item(Host, Node, ItemId).
|
||||||
|
|
||||||
|
get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
set_item(Item) ->
|
set_item(Item) ->
|
||||||
node_default:set_item(Item).
|
node_default:set_item(Item).
|
||||||
|
|
||||||
|
@ -62,7 +62,9 @@
|
|||||||
get_states/2,
|
get_states/2,
|
||||||
get_state/3,
|
get_state/3,
|
||||||
set_state/1,
|
set_state/1,
|
||||||
|
get_items/7,
|
||||||
get_items/2,
|
get_items/2,
|
||||||
|
get_item/8,
|
||||||
get_item/3,
|
get_item/3,
|
||||||
set_item/1,
|
set_item/1,
|
||||||
get_item_name/3
|
get_item_name/3
|
||||||
@ -96,7 +98,6 @@ features() ->
|
|||||||
["create-nodes",
|
["create-nodes",
|
||||||
"delete-nodes",
|
"delete-nodes",
|
||||||
"instant-nodes",
|
"instant-nodes",
|
||||||
"item-ids",
|
|
||||||
"outcast-affiliation",
|
"outcast-affiliation",
|
||||||
"persistent-items",
|
"persistent-items",
|
||||||
"publish",
|
"publish",
|
||||||
@ -175,9 +176,15 @@ set_state(State) ->
|
|||||||
get_items(Host, Node) ->
|
get_items(Host, Node) ->
|
||||||
node_default:get_items(Host, Node).
|
node_default:get_items(Host, Node).
|
||||||
|
|
||||||
|
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
get_item(Host, Node, ItemId) ->
|
get_item(Host, Node, ItemId) ->
|
||||||
node_default:get_item(Host, Node, ItemId).
|
node_default:get_item(Host, Node, ItemId).
|
||||||
|
|
||||||
|
get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
set_item(Item) ->
|
set_item(Item) ->
|
||||||
node_default:set_item(Item).
|
node_default:set_item(Item).
|
||||||
|
|
||||||
|
@ -62,7 +62,9 @@
|
|||||||
get_states/2,
|
get_states/2,
|
||||||
get_state/3,
|
get_state/3,
|
||||||
set_state/1,
|
set_state/1,
|
||||||
|
get_items/7,
|
||||||
get_items/2,
|
get_items/2,
|
||||||
|
get_item/8,
|
||||||
get_item/3,
|
get_item/3,
|
||||||
set_item/1,
|
set_item/1,
|
||||||
get_item_name/3
|
get_item_name/3
|
||||||
@ -96,7 +98,6 @@ features() ->
|
|||||||
["create-nodes",
|
["create-nodes",
|
||||||
"delete-nodes",
|
"delete-nodes",
|
||||||
"instant-nodes",
|
"instant-nodes",
|
||||||
"item-ids",
|
|
||||||
"outcast-affiliation",
|
"outcast-affiliation",
|
||||||
"persistent-items",
|
"persistent-items",
|
||||||
"publish",
|
"publish",
|
||||||
@ -172,9 +173,15 @@ set_state(State) ->
|
|||||||
get_items(Host, Node) ->
|
get_items(Host, Node) ->
|
||||||
node_default:get_items(Host, Node).
|
node_default:get_items(Host, Node).
|
||||||
|
|
||||||
|
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
get_item(Host, Node, ItemId) ->
|
get_item(Host, Node, ItemId) ->
|
||||||
node_default:get_item(Host, Node, ItemId).
|
node_default:get_item(Host, Node, ItemId).
|
||||||
|
|
||||||
|
get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
set_item(Item) ->
|
set_item(Item) ->
|
||||||
node_default:set_item(Item).
|
node_default:set_item(Item).
|
||||||
|
|
||||||
|
177
src/mod_pubsub/node_zoo.erl
Normal file
177
src/mod_pubsub/node_zoo.erl
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
%%% ====================================================================
|
||||||
|
%%% ``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 Process-one.
|
||||||
|
%%% Portions created by Process-one are Copyright 2006-2008, Process-one
|
||||||
|
%%% All Rights Reserved.''
|
||||||
|
%%% This software is copyright 2006-2008, Process-one.
|
||||||
|
%%%
|
||||||
|
%%% @copyright 2006-2008 Process-one
|
||||||
|
%%% @author Christophe romain <christophe.romain@process-one.net>
|
||||||
|
%%% [http://www.process-one.net/]
|
||||||
|
%%% @version {@vsn}, {@date} {@time}
|
||||||
|
%%% @end
|
||||||
|
%%% ====================================================================
|
||||||
|
|
||||||
|
-module(node_zoo).
|
||||||
|
-author('christophe.romain@process-one.net').
|
||||||
|
|
||||||
|
-include("pubsub.hrl").
|
||||||
|
-include("jlib.hrl").
|
||||||
|
|
||||||
|
-behaviour(gen_pubsub_node).
|
||||||
|
|
||||||
|
%% API definition
|
||||||
|
-export([init/3, terminate/2,
|
||||||
|
options/0, features/0,
|
||||||
|
create_node_permission/6,
|
||||||
|
create_node/3,
|
||||||
|
delete_node/2,
|
||||||
|
purge_node/3,
|
||||||
|
subscribe_node/8,
|
||||||
|
unsubscribe_node/5,
|
||||||
|
publish_item/7,
|
||||||
|
delete_item/4,
|
||||||
|
remove_extra_items/4,
|
||||||
|
get_entity_affiliations/2,
|
||||||
|
get_node_affiliations/2,
|
||||||
|
get_affiliation/3,
|
||||||
|
set_affiliation/4,
|
||||||
|
get_entity_subscriptions/2,
|
||||||
|
get_node_subscriptions/2,
|
||||||
|
get_subscription/3,
|
||||||
|
set_subscription/4,
|
||||||
|
get_states/2,
|
||||||
|
get_state/3,
|
||||||
|
set_state/1,
|
||||||
|
get_items/7,
|
||||||
|
get_items/2,
|
||||||
|
get_item/8,
|
||||||
|
get_item/3,
|
||||||
|
set_item/1
|
||||||
|
]).
|
||||||
|
|
||||||
|
|
||||||
|
init(Host, ServerHost, Opts) ->
|
||||||
|
node_default:init(Host, ServerHost, Opts).
|
||||||
|
|
||||||
|
terminate(Host, ServerHost) ->
|
||||||
|
node_default:terminate(Host, ServerHost).
|
||||||
|
|
||||||
|
options() ->
|
||||||
|
[{node_type, zoo},
|
||||||
|
{deliver_payloads, true},
|
||||||
|
{notify_config, false},
|
||||||
|
{notify_delete, false},
|
||||||
|
{notify_retract, true},
|
||||||
|
{persist_items, true},
|
||||||
|
{max_items, ?MAXITEMS div 2},
|
||||||
|
{subscribe, true},
|
||||||
|
{access_model, open},
|
||||||
|
{roster_groups_allowed, []},
|
||||||
|
{publish_model, publishers},
|
||||||
|
{max_payload_size, ?MAX_PAYLOAD_SIZE},
|
||||||
|
{send_last_published_item, never},
|
||||||
|
{deliver_notifications, true},
|
||||||
|
{presence_based_delivery, false}].
|
||||||
|
|
||||||
|
features() ->
|
||||||
|
node_default:features().
|
||||||
|
|
||||||
|
%% use same code as node_default, but do not limite node to
|
||||||
|
%% the home/localhost/user/... hierarchy
|
||||||
|
%% any node is allowed
|
||||||
|
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
|
||||||
|
LOwner = jlib:jid_tolower(Owner),
|
||||||
|
{User, Server, _Resource} = LOwner,
|
||||||
|
Allowed = case acl:match_rule(ServerHost, Access, LOwner) of
|
||||||
|
allow ->
|
||||||
|
true;
|
||||||
|
_ ->
|
||||||
|
case Owner of
|
||||||
|
{jid, "", _, "", "", _, ""} -> true;
|
||||||
|
_ -> false
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
{result, Allowed}.
|
||||||
|
|
||||||
|
create_node(Host, Node, Owner) ->
|
||||||
|
node_default:create_node(Host, Node, Owner).
|
||||||
|
|
||||||
|
delete_node(Host, Removed) ->
|
||||||
|
node_default:delete_node(Host, Removed).
|
||||||
|
|
||||||
|
subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup) ->
|
||||||
|
node_default:subscribe_node(Host, Node, Sender, Subscriber, AccessModel, SendLast, PresenceSubscription, RosterGroup).
|
||||||
|
|
||||||
|
unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
|
||||||
|
node_default:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
|
||||||
|
|
||||||
|
publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
|
||||||
|
node_default:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
|
||||||
|
|
||||||
|
remove_extra_items(Host, Node, MaxItems, ItemIds) ->
|
||||||
|
node_default:remove_extra_items(Host, Node, MaxItems, ItemIds).
|
||||||
|
|
||||||
|
delete_item(Host, Node, JID, ItemId) ->
|
||||||
|
node_default:delete_item(Host, Node, JID, ItemId).
|
||||||
|
|
||||||
|
purge_node(Host, Node, Owner) ->
|
||||||
|
node_default:purge_node(Host, Node, Owner).
|
||||||
|
|
||||||
|
get_entity_affiliations(Host, Owner) ->
|
||||||
|
node_default:get_entity_affiliations(Host, Owner).
|
||||||
|
|
||||||
|
get_node_affiliations(Host, Node) ->
|
||||||
|
node_default:get_node_affiliations(Host, Node).
|
||||||
|
|
||||||
|
get_affiliation(Host, Node, Owner) ->
|
||||||
|
node_default:get_affiliation(Host, Node, Owner).
|
||||||
|
|
||||||
|
set_affiliation(Host, Node, Owner, Affiliation) ->
|
||||||
|
node_default:set_affiliation(Host, Node, Owner, Affiliation).
|
||||||
|
|
||||||
|
get_entity_subscriptions(Host, Owner) ->
|
||||||
|
node_default:get_entity_subscriptions(Host, Owner).
|
||||||
|
|
||||||
|
get_node_subscriptions(Host, Node) ->
|
||||||
|
node_default:get_node_subscriptions(Host, Node).
|
||||||
|
|
||||||
|
get_subscription(Host, Node, Owner) ->
|
||||||
|
node_default:get_subscription(Host, Node, Owner).
|
||||||
|
|
||||||
|
set_subscription(Host, Node, Owner, Subscription) ->
|
||||||
|
node_default:set_subscription(Host, Node, Owner, Subscription).
|
||||||
|
|
||||||
|
get_states(Host, Node) ->
|
||||||
|
node_default:get_states(Host, Node).
|
||||||
|
|
||||||
|
get_state(Host, Node, JID) ->
|
||||||
|
node_default:get_state(Host, Node, JID).
|
||||||
|
|
||||||
|
set_state(State) ->
|
||||||
|
node_default:set_state(State).
|
||||||
|
|
||||||
|
get_items(Host, Node) ->
|
||||||
|
node_default:get_items(Host, Node).
|
||||||
|
|
||||||
|
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
|
get_item(Host, Node, ItemId) ->
|
||||||
|
node_default:get_item(Host, Node, ItemId).
|
||||||
|
|
||||||
|
get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
|
||||||
|
node_default:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
|
||||||
|
|
||||||
|
set_item(Item) ->
|
||||||
|
node_default:set_item(Item).
|
@ -290,7 +290,7 @@ process_request(#state{request_method = Method,
|
|||||||
LQ
|
LQ
|
||||||
end,
|
end,
|
||||||
LPath = string:tokens(NPath, "/"),
|
LPath = string:tokens(NPath, "/"),
|
||||||
{ok, {IP, _Port}} =
|
{ok, IP} =
|
||||||
case SockMod of
|
case SockMod of
|
||||||
gen_tcp ->
|
gen_tcp ->
|
||||||
inet:peername(Socket);
|
inet:peername(Socket);
|
||||||
@ -302,7 +302,7 @@ process_request(#state{request_method = Method,
|
|||||||
q = LQuery,
|
q = LQuery,
|
||||||
auth = Auth,
|
auth = Auth,
|
||||||
lang = Lang,
|
lang = Lang,
|
||||||
ip=IP},
|
ip = IP},
|
||||||
%% XXX bard: This previously passed control to
|
%% XXX bard: This previously passed control to
|
||||||
%% ejabberd_web:process_get, now passes it to a local
|
%% ejabberd_web:process_get, now passes it to a local
|
||||||
%% procedure (process) that handles dispatching based on
|
%% procedure (process) that handles dispatching based on
|
||||||
@ -348,12 +348,20 @@ process_request(#state{request_method = Method,
|
|||||||
LQ ->
|
LQ ->
|
||||||
LQ
|
LQ
|
||||||
end,
|
end,
|
||||||
|
{ok, IP} =
|
||||||
|
case SockMod of
|
||||||
|
gen_tcp ->
|
||||||
|
inet:peername(Socket);
|
||||||
|
_ ->
|
||||||
|
SockMod:peername(Socket)
|
||||||
|
end,
|
||||||
Request = #request{method = Method,
|
Request = #request{method = Method,
|
||||||
path = LPath,
|
path = LPath,
|
||||||
q = LQuery,
|
q = LQuery,
|
||||||
auth = Auth,
|
auth = Auth,
|
||||||
data = Data,
|
data = Data,
|
||||||
lang = Lang},
|
lang = Lang,
|
||||||
|
ip = IP},
|
||||||
case process(RequestHandlers, Request) of
|
case process(RequestHandlers, Request) of
|
||||||
El when element(1, El) == xmlelement ->
|
El when element(1, El) == xmlelement ->
|
||||||
make_xhtml_output(State, 200, [], El);
|
make_xhtml_output(State, 200, [], El);
|
||||||
|
@ -50,13 +50,16 @@
|
|||||||
|
|
||||||
-record(http_poll, {id, pid}).
|
-record(http_poll, {id, pid}).
|
||||||
|
|
||||||
|
-define(NULL_PEER, {{0, 0, 0, 0}, 0}).
|
||||||
|
|
||||||
-record(state, {id,
|
-record(state, {id,
|
||||||
key,
|
key,
|
||||||
output = "",
|
output = "",
|
||||||
input = "",
|
input = "",
|
||||||
waiting_input = false, %% {ReceiverPid, Tag}
|
waiting_input = false, %% {ReceiverPid, Tag}
|
||||||
last_receiver,
|
last_receiver,
|
||||||
timer}).
|
timer,
|
||||||
|
ip = ?NULL_PEER }).
|
||||||
|
|
||||||
%-define(DBGFSM, true).
|
%-define(DBGFSM, true).
|
||||||
|
|
||||||
@ -94,11 +97,18 @@ setopts({http_poll, FsmRef}, Opts) ->
|
|||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
sockname(_Socket) ->
|
sockname(_) ->
|
||||||
{ok, {{0, 0, 0, 0}, 0}}.
|
{ok, ?NULL_PEER}.
|
||||||
|
|
||||||
peername(_Socket) ->
|
peername({http_poll, FsmRef}) ->
|
||||||
{ok, {{0, 0, 0, 0}, 0}}.
|
gen_fsm:send_all_state_event(FsmRef, {peername, self()}),
|
||||||
|
%% XXX should improve that, but sync call seems not possible
|
||||||
|
receive
|
||||||
|
{peername, PeerName} -> {ok, PeerName}
|
||||||
|
after 1000 -> {ok, ?NULL_PEER}
|
||||||
|
end;
|
||||||
|
peername(_) ->
|
||||||
|
{ok, ?NULL_PEER}.
|
||||||
|
|
||||||
controlling_process(_Socket, _Pid) ->
|
controlling_process(_Socket, _Pid) ->
|
||||||
ok.
|
ok.
|
||||||
@ -107,7 +117,7 @@ close({http_poll, FsmRef}) ->
|
|||||||
catch gen_fsm:sync_send_all_state_event(FsmRef, close).
|
catch gen_fsm:sync_send_all_state_event(FsmRef, close).
|
||||||
|
|
||||||
|
|
||||||
process([], #request{data = Data} = _Request) ->
|
process([], #request{data = Data, ip = IP} = _Request) ->
|
||||||
case catch parse_request(Data) of
|
case catch parse_request(Data) of
|
||||||
{ok, ID1, Key, NewKey, Packet} ->
|
{ok, ID1, Key, NewKey, Packet} ->
|
||||||
ID = if
|
ID = if
|
||||||
@ -123,7 +133,7 @@ process([], #request{data = Data} = _Request) ->
|
|||||||
true ->
|
true ->
|
||||||
ID1
|
ID1
|
||||||
end,
|
end,
|
||||||
case http_put(ID, Key, NewKey, Packet) of
|
case http_put(ID, Key, NewKey, Packet, IP) of
|
||||||
{error, not_exists} ->
|
{error, not_exists} ->
|
||||||
{200, ?BAD_REQUEST, ""};
|
{200, ?BAD_REQUEST, ""};
|
||||||
{error, bad_key} ->
|
{error, bad_key} ->
|
||||||
@ -228,6 +238,10 @@ handle_event({activate, From}, StateName, StateData) ->
|
|||||||
}}
|
}}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
handle_event({peername, From}, StateName, StateData) ->
|
||||||
|
From ! {peername, StateData#state.ip},
|
||||||
|
{next_state, StateName, StateData};
|
||||||
|
|
||||||
handle_event(_Event, StateName, StateData) ->
|
handle_event(_Event, StateName, StateData) ->
|
||||||
{next_state, StateName, StateData}.
|
{next_state, StateName, StateData}.
|
||||||
|
|
||||||
@ -249,7 +263,7 @@ handle_sync_event(stop, _From, _StateName, StateData) ->
|
|||||||
Reply = ok,
|
Reply = ok,
|
||||||
{stop, normal, Reply, StateData};
|
{stop, normal, Reply, StateData};
|
||||||
|
|
||||||
handle_sync_event({http_put, Key, NewKey, Packet},
|
handle_sync_event({http_put, Key, NewKey, Packet, IP},
|
||||||
_From, StateName, StateData) ->
|
_From, StateName, StateData) ->
|
||||||
Allow = case StateData#state.key of
|
Allow = case StateData#state.key of
|
||||||
"" ->
|
"" ->
|
||||||
@ -271,7 +285,8 @@ handle_sync_event({http_put, Key, NewKey, Packet},
|
|||||||
Input = [StateData#state.input|Packet],
|
Input = [StateData#state.input|Packet],
|
||||||
Reply = ok,
|
Reply = ok,
|
||||||
{reply, Reply, StateName, StateData#state{input = Input,
|
{reply, Reply, StateName, StateData#state{input = Input,
|
||||||
key = NewKey}};
|
key = NewKey,
|
||||||
|
ip = IP}};
|
||||||
{Receiver, _Tag} ->
|
{Receiver, _Tag} ->
|
||||||
Receiver ! {tcp, {http_poll, self()},
|
Receiver ! {tcp, {http_poll, self()},
|
||||||
list_to_binary(Packet)},
|
list_to_binary(Packet)},
|
||||||
@ -282,7 +297,8 @@ handle_sync_event({http_put, Key, NewKey, Packet},
|
|||||||
StateData#state{waiting_input = false,
|
StateData#state{waiting_input = false,
|
||||||
last_receiver = Receiver,
|
last_receiver = Receiver,
|
||||||
key = NewKey,
|
key = NewKey,
|
||||||
timer = Timer}}
|
timer = Timer,
|
||||||
|
ip = IP}}
|
||||||
end;
|
end;
|
||||||
true ->
|
true ->
|
||||||
Reply = {error, bad_key},
|
Reply = {error, bad_key},
|
||||||
@ -343,13 +359,13 @@ terminate(_Reason, _StateName, StateData) ->
|
|||||||
%%% Internal functions
|
%%% Internal functions
|
||||||
%%%----------------------------------------------------------------------
|
%%%----------------------------------------------------------------------
|
||||||
|
|
||||||
http_put(ID, Key, NewKey, Packet) ->
|
http_put(ID, Key, NewKey, Packet, IP) ->
|
||||||
case mnesia:dirty_read({http_poll, ID}) of
|
case mnesia:dirty_read({http_poll, ID}) of
|
||||||
[] ->
|
[] ->
|
||||||
{error, not_exists};
|
{error, not_exists};
|
||||||
[#http_poll{pid = FsmRef}] ->
|
[#http_poll{pid = FsmRef}] ->
|
||||||
gen_fsm:sync_send_all_state_event(
|
gen_fsm:sync_send_all_state_event(
|
||||||
FsmRef, {http_put, Key, NewKey, Packet})
|
FsmRef, {http_put, Key, NewKey, Packet, IP})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
http_get(ID) ->
|
http_get(ID) ->
|
||||||
|
Loading…
Reference in New Issue
Block a user