fix dializer errors, improve documentation (thanks to Karim Gemayel)(EJAB-1260)
This commit is contained in:
parent
f7dc4df784
commit
6b7d73dcd5
File diff suppressed because it is too large
Load Diff
|
@ -42,7 +42,8 @@
|
|||
|
||||
-behaviour(gen_pubsub_nodetree).
|
||||
|
||||
-export([init/3,
|
||||
-export([
|
||||
init/3,
|
||||
terminate/2,
|
||||
options/0,
|
||||
set_node/1,
|
||||
|
@ -60,6 +61,7 @@
|
|||
]).
|
||||
|
||||
|
||||
|
||||
%% ================
|
||||
%% API definition
|
||||
%% ================
|
||||
|
@ -73,6 +75,14 @@
|
|||
%% <p>This function is mainly used to trigger the setup task necessary for the
|
||||
%% plugin. It can be used for example by the developer to create the specific
|
||||
%% module database schema if it does not exists yet.</p>
|
||||
-spec(init/3 ::
|
||||
(
|
||||
Host :: string(),
|
||||
ServerHost :: string(),
|
||||
Opts :: [{Key::atom(), Value::term()}])
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
init(_Host, _ServerHost, _Opts) ->
|
||||
mnesia:create_table(pubsub_node,
|
||||
[{disc_copies, [node()]},
|
||||
|
@ -81,49 +91,101 @@ init(_Host, _ServerHost, _Opts) ->
|
|||
NodesFields = record_info(fields, pubsub_node),
|
||||
case mnesia:table_info(pubsub_node, attributes) of
|
||||
NodesFields -> ok;
|
||||
_ ->
|
||||
ok
|
||||
%% mnesia:transform_table(pubsub_state, ignore, StatesFields)
|
||||
_ -> ok %% mnesia:transform_table(pubsub_state, ignore, StatesFields)
|
||||
end,
|
||||
ok.
|
||||
|
||||
|
||||
-spec(terminate/2 ::
|
||||
(
|
||||
Host :: string(),
|
||||
ServerHost :: string())
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
terminate(_Host, _ServerHost) ->
|
||||
ok.
|
||||
|
||||
%% @spec () -> [Option]
|
||||
%% Option = mod_pubsub:nodetreeOption()
|
||||
%% @doc Returns the default pubsub node tree options.
|
||||
options() ->
|
||||
[{virtual_tree, false}].
|
||||
-spec(options/0 :: () -> Options::[{'virtual_tree', 'false'}]).
|
||||
|
||||
options() -> [{'virtual_tree', 'false'}].
|
||||
|
||||
%% @spec (NodeRecord) -> ok | {error, Reason}
|
||||
%% Record = mod_pubsub:pubsub_node()
|
||||
set_node(Record) when is_record(Record, pubsub_node) ->
|
||||
mnesia:write(Record);
|
||||
set_node(_) ->
|
||||
{error, 'internal-server-error'}.
|
||||
%(
|
||||
% Node :: pubsubNode() -> 'ok' | {'error', Reason::_};
|
||||
% Node :: any() -> {'error', 'internal-server-error'}
|
||||
%).
|
||||
%% -spec breaks compilation
|
||||
|
||||
set_node(#pubsub_node{} = Node) -> mnesia:write(Node);
|
||||
set_node(_) -> {error, 'internal-server-error'}.
|
||||
|
||||
%% @spec (Host, Node, From) -> pubsubNode() | {error, Reason}
|
||||
%% Host = mod_pubsub:host()
|
||||
%% Node = node()
|
||||
get_node(Host, Node, _From) ->
|
||||
get_node(Host, Node).
|
||||
get_node(Host, Node) ->
|
||||
case catch mnesia:read({pubsub_node, {Host, Node}}) of
|
||||
[Record] when is_record(Record, pubsub_node) -> Record;
|
||||
[] -> {error, 'item-not-found'};
|
||||
Error -> Error
|
||||
-spec(get_node/3 ::
|
||||
(
|
||||
Host :: host(), % hostPubsub | hostPEP()
|
||||
NodeId :: nodeId(),
|
||||
JID :: jidEntity())
|
||||
-> pubsubNode() | {error, 'item-not-found'} | any()
|
||||
).
|
||||
|
||||
get_node(Host, NodeId, _JID) ->
|
||||
get_node(Host, NodeId).
|
||||
|
||||
|
||||
-spec(get_node/2 ::
|
||||
(
|
||||
Host :: host(), % hostPubsub | hostPEP()
|
||||
NodeId :: nodeId())
|
||||
-> pubsubNode() | {error, 'item-not-found'} | any()
|
||||
).
|
||||
|
||||
get_node(Host, NodeId) ->
|
||||
case catch mnesia:read({pubsub_node, {Host, NodeId}}) of
|
||||
[#pubsub_node{} = Node] -> Node;
|
||||
[] -> {error, 'item-not-found'};
|
||||
Error -> Error
|
||||
end.
|
||||
get_node(Nidx) ->
|
||||
case catch mnesia:index_read(pubsub_node, Nidx, #pubsub_node.idx) of
|
||||
[Record] when is_record(Record, pubsub_node) -> Record;
|
||||
[] -> {error, 'item-not-found'};
|
||||
Error -> Error
|
||||
|
||||
|
||||
-spec(get_node/1 ::
|
||||
(
|
||||
NodeIdx :: nodeIdx())
|
||||
-> pubsubNode() | {error, 'item-not-found'} | any()
|
||||
).
|
||||
|
||||
get_node(NodeIdx) ->
|
||||
case catch mnesia:index_read(pubsub_node, NodeIdx, #pubsub_node.idx) of
|
||||
[#pubsub_node{} = Node] -> Node;
|
||||
[] -> {error, 'item-not-found'};
|
||||
Error -> Error
|
||||
end.
|
||||
|
||||
%% @spec (Host, From) -> [pubsubNode()] | {error, Reason}
|
||||
%% Host = mod_pubsub:host() | ljid()
|
||||
get_nodes(Host, _From) ->
|
||||
-spec(get_nodes/2 ::
|
||||
(
|
||||
Host :: host(), % hostPubsub | hostPEP()
|
||||
JID :: jidEntity())
|
||||
-> Nodes :: [] | [Node::pubsubNode()]
|
||||
).
|
||||
|
||||
get_nodes(Host, _JID) ->
|
||||
get_nodes(Host).
|
||||
|
||||
|
||||
-spec(get_nodes/1 ::
|
||||
(
|
||||
Host :: host()) % hostPubsub | hostPEP()
|
||||
-> Nodes :: [] | [Node::pubsubNode()]
|
||||
).
|
||||
|
||||
get_nodes(Host) ->
|
||||
mnesia:match_object(#pubsub_node{id = {Host, '_'}, _ = '_'}).
|
||||
|
||||
|
@ -134,7 +196,15 @@ get_nodes(Host) ->
|
|||
%% Depth = integer()
|
||||
%% Record = pubsubNode()
|
||||
%% @doc <p>Default node tree does not handle parents, return empty list.</p>
|
||||
get_parentnodes(_Host, _Node, _From) ->
|
||||
-spec(get_parentnodes/3 ::
|
||||
(
|
||||
Host :: host(), % hostPubsub | hostPEP()
|
||||
NodeId :: nodeId(),
|
||||
JID :: jidEntity())
|
||||
-> ParentNodes :: []
|
||||
).
|
||||
|
||||
get_parentnodes(_Host, _NodeId, _JID) ->
|
||||
[].
|
||||
|
||||
%% @spec (Host, Node, From) -> [{Depth, Record}] | {error, Reason}
|
||||
|
@ -145,52 +215,98 @@ get_parentnodes(_Host, _Node, _From) ->
|
|||
%% Record = pubsubNode()
|
||||
%% @doc <p>Default node tree does not handle parents, return a list
|
||||
%% containing just this node.</p>
|
||||
get_parentnodes_tree(Host, Node, From) ->
|
||||
case get_node(Host, Node, From) of
|
||||
N when is_record(N, pubsub_node) -> [{0, [N]}];
|
||||
_Error -> []
|
||||
-spec(get_parentnodes_tree/3 ::
|
||||
(
|
||||
Host :: host(), % hostPubsub | hostPEP()
|
||||
NodeId :: nodeId(),
|
||||
JID :: jidEntity())
|
||||
-> ParentNodesTree :: [] | [{0, [ParentNode::pubsubNode()]}]
|
||||
).
|
||||
|
||||
get_parentnodes_tree(Host, NodeId, JID) ->
|
||||
case get_node(Host, NodeId, JID) of
|
||||
#pubsub_node{} = ParentNode -> [{0, [ParentNode]}];
|
||||
_Error -> []
|
||||
end.
|
||||
|
||||
%% @spec (Host, Node, From) -> [pubsubNode()] | {error, Reason}
|
||||
%% Host = mod_pubsub:host()
|
||||
%% Node = node()
|
||||
%% From = ljid()
|
||||
get_subnodes(Host, Node, _From) ->
|
||||
get_subnodes(Host, Node).
|
||||
get_subnodes(Host, <<>>) ->
|
||||
Q = qlc:q([N || #pubsub_node{id = {NHost, _},
|
||||
parents = Parents} = N <- mnesia:table(pubsub_node),
|
||||
Host == NHost,
|
||||
Parents == []]),
|
||||
-spec(get_subnodes/3 ::
|
||||
(
|
||||
Host :: host(), % hostPubsub | hostPEP()
|
||||
NodeId :: nodeId(),
|
||||
JID :: jidEntity())
|
||||
-> SubNodes :: [] | [Node::pubsubNode()]
|
||||
).
|
||||
|
||||
get_subnodes(Host, NodeId, _JID) ->
|
||||
get_subnodes(Host, NodeId).
|
||||
|
||||
|
||||
-spec(get_subnodes/2 ::
|
||||
(
|
||||
ParentNodeHost :: host(), % hostPubsub | hostPEP()
|
||||
ParentNodeId :: nodeId())
|
||||
-> SubNodes :: [] | [Node::pubsubNode()]
|
||||
).
|
||||
|
||||
get_subnodes(ParentNodeHost, <<>>) ->
|
||||
Q = qlc:q(
|
||||
[Node
|
||||
|| #pubsub_node{id = {Host, _}, parents = ParentNodeIds} = Node
|
||||
<- mnesia:table(pubsub_node),
|
||||
ParentNodeHost == Host,
|
||||
ParentNodeIds == []]),
|
||||
qlc:e(Q);
|
||||
get_subnodes(Host, Node) ->
|
||||
Q = qlc:q([N || #pubsub_node{id = {NHost, _},
|
||||
parents = Parents} = N <- mnesia:table(pubsub_node),
|
||||
Host == NHost,
|
||||
lists:member(Node, Parents)]),
|
||||
get_subnodes(ParentNodeHost, ParentNodeId) ->
|
||||
Q = qlc:q(
|
||||
[Node
|
||||
|| #pubsub_node{id = {Host, _}, parents = ParentNodeIds} = Node
|
||||
<- mnesia:table(pubsub_node),
|
||||
ParentNodeHost == Host,
|
||||
lists:member(ParentNodeId, ParentNodeIds)]),
|
||||
qlc:e(Q).
|
||||
|
||||
%% @spec (Host, Index, From) -> [nodeidx()] | {error, Reason}
|
||||
%% Host = mod_pubsub:host()
|
||||
%% Node = node()
|
||||
%% From = ljid()
|
||||
get_subnodes_tree(Host, Node, _From) ->
|
||||
get_subnodes_tree(Host, Node).
|
||||
get_subnodes_tree(Host, Node) ->
|
||||
case get_node(Host, Node) of
|
||||
{error, _} ->
|
||||
[];
|
||||
Rec ->
|
||||
BasePlugin = list_to_atom("node_"++Rec#pubsub_node.type),
|
||||
BasePath = BasePlugin:node_to_path(Node),
|
||||
mnesia:foldl(fun(#pubsub_node{id = {H, N}} = R, Acc) ->
|
||||
Plugin = list_to_atom("node_"++R#pubsub_node.type),
|
||||
Path = Plugin:node_to_path(N),
|
||||
case lists:prefix(BasePath, Path) and (H == Host) of
|
||||
true -> [R | Acc];
|
||||
false -> Acc
|
||||
end
|
||||
end, [], pubsub_node)
|
||||
-spec(get_subnodes_tree/3 ::
|
||||
(
|
||||
Host :: host(), % hostPubsub | hostPEP()
|
||||
ParentNodeId :: nodeId(),
|
||||
JID :: jidEntity())
|
||||
-> SubNodes :: [] | [Node::pubsubNode()]
|
||||
).
|
||||
|
||||
get_subnodes_tree(Host, ParentNodeId, _JID) ->
|
||||
get_subnodes_tree(Host, ParentNodeId).
|
||||
|
||||
|
||||
-spec(get_subnodes_tree/2 ::
|
||||
(
|
||||
Host :: host(), % hostPubsub | hostPEP()
|
||||
ParentNodeId :: nodeId())
|
||||
-> SubNodes :: [] | [Node::pubsubNode()]
|
||||
).
|
||||
|
||||
get_subnodes_tree(ParentNodeHost, ParentNodeId) ->
|
||||
case get_node(ParentNodeHost, ParentNodeId) of
|
||||
{error, _} -> [];
|
||||
#pubsub_node{type = ParentNodeType} = _ParentNode ->
|
||||
BasePlugin = list_to_atom("node_"++ParentNodeType),
|
||||
BasePath = BasePlugin:node_to_path(ParentNodeId),
|
||||
mnesia:foldl(fun
|
||||
(#pubsub_node{id = {Host, NodeId}, type = Type} = Node, Acc) ->
|
||||
Plugin = list_to_atom("node_"++Type),
|
||||
Path = Plugin:node_to_path(NodeId),
|
||||
case lists:prefix(BasePath, Path) and (Host == ParentNodeHost) of
|
||||
true -> [Node | Acc];
|
||||
false -> Acc
|
||||
end
|
||||
end, [], pubsub_node)
|
||||
end.
|
||||
|
||||
%% @spec (Host, Node, Type, Owner, Options, Parents) -> ok | {error, Reason}
|
||||
|
@ -199,56 +315,70 @@ get_subnodes_tree(Host, Node) ->
|
|||
%% NodeType = nodeType()
|
||||
%% Owner = ljid()
|
||||
%% Options = list()
|
||||
create_node(Host, Node, Type, Owner, Options, Parents) ->
|
||||
BJID = jlib:short_prepd_bare_jid(Owner),
|
||||
case mnesia:read({pubsub_node, {Host, Node}}) of
|
||||
-spec(create_node/6 ::
|
||||
(
|
||||
Host :: host(), % hostPubsub | hostPEP()
|
||||
NodeId :: nodeId(),
|
||||
Type :: nodeType(),
|
||||
JID :: jidEntity(),
|
||||
Options :: [nodeOption()],
|
||||
ParentNodeIds :: [] | [nodeId()])
|
||||
-> {'ok', NodeIdx::nodeIdx()}
|
||||
| {'error', 'conflict' | 'forbidden'}
|
||||
).
|
||||
|
||||
create_node(Host, NodeId, Type, #jid{node = U, domain = S} = _JID, Options, ParentNodeIds) ->
|
||||
Owner = {U,S,undefined},
|
||||
case mnesia:read({pubsub_node, {Host, NodeId}}) of
|
||||
[] ->
|
||||
ParentExists =
|
||||
case Host of
|
||||
{_U, _S, _R} ->
|
||||
%% This is special case for PEP handling
|
||||
%% PEP does not uses hierarchy
|
||||
true;
|
||||
_ ->
|
||||
case Parents of
|
||||
[] -> true;
|
||||
[Parent | _] ->
|
||||
BHost = list_to_binary(Host),
|
||||
case mnesia:read({pubsub_node, {Host, Parent}}) of
|
||||
[#pubsub_node{owners = [{undefined, BHost, undefined}]}] -> true;
|
||||
[#pubsub_node{owners = Owners}] -> lists:member(BJID, Owners);
|
||||
_ -> false
|
||||
end;
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end,
|
||||
ParentExists = case Host of
|
||||
%% This is special case for PEP handling, PEP does not uses hierarchy
|
||||
{_, _, _} -> true;
|
||||
_ ->
|
||||
case ParentNodeIds of
|
||||
[] -> true;
|
||||
[ParentNodeId | _] ->
|
||||
case mnesia:read({pubsub_node, {Host, ParentNodeId}}) of
|
||||
[#pubsub_node{owners = [{undefined, Host, undefined}]}] -> true;
|
||||
[#pubsub_node{owners = Owners}] -> lists:member(Owner, Owners);
|
||||
_ -> false
|
||||
end;
|
||||
_ -> false
|
||||
end
|
||||
end,
|
||||
case ParentExists of
|
||||
true ->
|
||||
Nidx = pubsub_index:new(node),
|
||||
mnesia:write(#pubsub_node{id = {Host, Node},
|
||||
idx = Nidx,
|
||||
parents = Parents,
|
||||
type = Type,
|
||||
owners = [BJID],
|
||||
options = Options}),
|
||||
{ok, Nidx};
|
||||
false ->
|
||||
%% Requesting entity is prohibited from creating nodes
|
||||
{error, 'forbidden'}
|
||||
end;
|
||||
_ ->
|
||||
%% Node already exists
|
||||
{error, 'conflict'}
|
||||
NodeIdx = pubsub_index:new(node),
|
||||
mnesia:write(
|
||||
#pubsub_node{
|
||||
id = {Host, NodeId},
|
||||
idx = NodeIdx,
|
||||
parents = ParentNodeIds,
|
||||
type = Type,
|
||||
owners = [Owner],
|
||||
options = Options}),
|
||||
{ok, NodeIdx};
|
||||
false -> %% Requesting entity is prohibited from creating nodes
|
||||
{error, 'forbidden'}
|
||||
end;
|
||||
_ -> %% Node already exists
|
||||
{error, 'conflict'}
|
||||
end.
|
||||
|
||||
%% @spec (Host, Node) -> [mod_pubsub:node()]
|
||||
%% Host = mod_pubsub:host() | ljid()
|
||||
%% Node = node()
|
||||
delete_node(Host, Node) ->
|
||||
Removed = get_subnodes_tree(Host, Node),
|
||||
lists:foreach(fun(#pubsub_node{id = {_, N}, idx = I}) ->
|
||||
pubsub_index:free(node, I),
|
||||
mnesia:delete({pubsub_node, {Host, N}})
|
||||
end, Removed),
|
||||
Removed.
|
||||
-spec(delete_node/2 ::
|
||||
(
|
||||
Host :: host(), % hostPubsub | hostPEP()
|
||||
ParentNodeId :: nodeId())
|
||||
-> DeletedNodes :: [] | [Node::pubsubNode()]
|
||||
).
|
||||
|
||||
delete_node(Host, ParentNodeId) ->
|
||||
DeletedNodes = get_subnodes_tree(Host, ParentNodeId),
|
||||
lists:foreach(fun(#pubsub_node{id = {_, NodeId}, idx = NodeIdx}) ->
|
||||
pubsub_index:free(node, NodeIdx),
|
||||
mnesia:delete({pubsub_node, {Host, NodeId}})
|
||||
end, DeletedNodes),
|
||||
DeletedNodes.
|
||||
|
|
|
@ -42,14 +42,25 @@
|
|||
%% Pubsub types
|
||||
%% ------------
|
||||
|
||||
%%% @type host() = binary().
|
||||
%%% @type hostPubsub() = binary().
|
||||
%%%
|
||||
%%% <p><tt>host</tt> is the name of the PubSub service. For example, it can be
|
||||
%%% <p><tt>hostPubsub</tt> is the name of the PubSub service. For example, it can be
|
||||
%%% <tt>pubsub.localhost</tt>.</p>
|
||||
|
||||
-type(host() :: binary()).
|
||||
-type(hostPubsub() :: binary()).
|
||||
|
||||
|
||||
%%% @type hostPEP() = {User::binary(), Server::binary, Resource::undefined}.
|
||||
|
||||
-type(hostPEP() :: {User::binary(), Server::binary, Resource::undefined}).
|
||||
|
||||
|
||||
%%% @type host() = hostPubsub() | hostPEP().
|
||||
|
||||
-type(host() :: hostPubsub() | hostPEP()).
|
||||
|
||||
|
||||
%% TODO : move upper in exmpp
|
||||
%%% @type nodeId() = binary().
|
||||
%%%
|
||||
%%% <p>A <tt>nodeId</tt> is the name of a Node. It can be anything and may represent
|
||||
|
@ -93,6 +104,58 @@
|
|||
-type(ljid() :: {User::binary(), Server::binary(), Resource::binary()}).
|
||||
|
||||
|
||||
%% TODO : move upper in exmpp
|
||||
%%% @type jidComponent() =
|
||||
%% #jid{raw::binary(), node::undefined, domain::binary(), resource::undefined}.
|
||||
|
||||
-type(jidComponent() ::
|
||||
#jid{raw::binary(), node::undefined, domain::binary(), resource::undefined}).
|
||||
|
||||
|
||||
%% TODO : move upper in exmpp
|
||||
%%% @type jidContact() =
|
||||
%% #jid{raw::binary(), node::binary(), domain::binary(), resource::undefined}.
|
||||
|
||||
-type(jidContact() ::
|
||||
#jid{raw::binary(), node::binary(), domain::binary(), resource::undefined}).
|
||||
|
||||
|
||||
%% TODO : move upper in exmpp
|
||||
%%% @type jidEntity() =
|
||||
%%% #jid{raw::binary(), node::binary(), domain::binary(), resource::undefined}
|
||||
%%% #jid{raw::binary(), node::binary(), domain::binary(), resource::binary()}
|
||||
%%% #jid{raw::binary(), node::undefined, domain::binary(), resource::undefined}
|
||||
%%% #jid{raw::binary(), node::undefined, domain::binary(), resource::binary()}.
|
||||
|
||||
-type(jidEntity() ::
|
||||
%% Contact bare JID
|
||||
#jid{raw::binary(), node::binary(), domain::binary(), resource::undefined} |
|
||||
%% Contact full JID
|
||||
#jid{raw::binary(), node::binary(), domain::binary(), resource::binary()} |
|
||||
%% Component bare JID
|
||||
#jid{raw::binary(), node::undefined, domain::binary(), resource::undefined} |
|
||||
%% Component full JID
|
||||
#jid{raw::binary(), node::undefined, domain::binary(), resource::binary()}).
|
||||
|
||||
|
||||
%%% @type bareUsr() = {User::binary(), Server::binary(), Resource::undefined}
|
||||
%%% | {User::undefined, Server::binary(), Resource::undefined}.
|
||||
|
||||
-type(bareUsr() :: {User::binary(), Server::binary(), Resource::undefined}
|
||||
| {User::undefined, Server::binary(), Resource::undefined}).
|
||||
|
||||
|
||||
%%% @type fullUsr() = {User::binary(), Server::binary(), Resource::undefined}
|
||||
%%% | {User::binary(), Server::binary(), Resource::binary()}
|
||||
%%% | {User::undefined, Server::binary(), Resource::undefined}
|
||||
%%% | {User::undefined, Server::binary(), Resource::binary()}.
|
||||
|
||||
-type(fullUsr() :: {User::binary(), Server::binary(), Resource::undefined}
|
||||
| {User::binary(), Server::binary(), Resource::binary()}
|
||||
| {User::undefined, Server::binary(), Resource::undefined}
|
||||
| {User::undefined, Server::binary(), Resource::binary()}).
|
||||
|
||||
|
||||
%%% @type nodeIdx() = integer().
|
||||
|
||||
-type(nodeIdx() :: integer()).
|
||||
|
@ -103,19 +166,24 @@
|
|||
-type(now() :: {Megaseconds::integer(), Seconds::integer(), Microseconds::integer()}).
|
||||
|
||||
|
||||
%%% @type affiliation() = none | owner | publisher | member | outcast.
|
||||
%%% @type affiliation() = 'none' | 'owner' | 'publisher' |'publish-only' | 'member' | 'outcast'.
|
||||
|
||||
-type(affiliation() :: none | owner | publisher | member | outcast).
|
||||
-type(affiliation() :: 'none' | 'owner' | 'publisher' |'publish-only' | 'member' | 'outcast').
|
||||
|
||||
|
||||
%%% @type subscription() = none | pending | unconfigured | subscribed.
|
||||
%%% @type subscription() = 'none' | 'pending' | 'unconfigured' | 'subscribed'.
|
||||
|
||||
-type(subscription() :: none | pending | unconfigured | subscribed).
|
||||
-type(subscription() :: 'none' | 'pending' | 'unconfigured' | 'subscribed').
|
||||
|
||||
|
||||
%%% @type payload() = string().
|
||||
%%% @type accessModel() = 'open' | 'presence' | 'roster' | 'authorize' | 'whitelist'.
|
||||
|
||||
-type(payload() :: string()).
|
||||
-type(accessModel() :: 'open' | 'presence' | 'roster' | 'authorize' | 'whitelist').
|
||||
|
||||
|
||||
%%% @type payload() = [] | [#xmlel{}].
|
||||
|
||||
-type(payload() :: [] | [#xmlel{}]).
|
||||
|
||||
|
||||
%%% @type stanzaError() = #xmlel{}.
|
||||
|
@ -155,6 +223,10 @@
|
|||
-type(pubsubIQResponse() :: #xmlel{}).
|
||||
|
||||
|
||||
%%% @type features() = [Feature::string()].
|
||||
|
||||
-type(features() :: [Feature::string()]).
|
||||
|
||||
%%% @type nodeOption() = {Option, Value}.
|
||||
%%% Option = atom()
|
||||
%%% Value = term().
|
||||
|
@ -164,6 +236,7 @@
|
|||
|
||||
-type(nodeOption() :: {Option::atom(), Value::term()}).
|
||||
|
||||
|
||||
%%% @type subOption() = {Option, Value}.
|
||||
%%% Option = atom()
|
||||
%%% Value = term().
|
||||
|
@ -179,11 +252,11 @@
|
|||
%%% Internal pubsub index table.
|
||||
|
||||
-record(pubsub_index,
|
||||
{
|
||||
index :: atom(),
|
||||
last :: integer(),
|
||||
free :: [integer()]
|
||||
}).
|
||||
{
|
||||
index :: atom(),
|
||||
last :: integer(),
|
||||
free :: [integer()]
|
||||
}).
|
||||
|
||||
-type(pubsubIndex() :: #pubsub_index{}).
|
||||
|
||||
|
@ -193,7 +266,7 @@
|
|||
%%% Idx = nodeIdx()
|
||||
%%% Parents = [nodeId()]
|
||||
%%% Type = nodeType()
|
||||
%%% Owners = [ljid()]
|
||||
%%% Owners = [bareUsr()]
|
||||
%%% Options = [nodeOption()].
|
||||
%%%
|
||||
%%% <p>This is the format of the <tt>nodes</tt> table. The type of the table
|
||||
|
@ -202,54 +275,54 @@
|
|||
%%% <p><tt>idx</tt> is an integer.</p>
|
||||
|
||||
-record(pubsub_node,
|
||||
{
|
||||
id :: {host(), nodeId()},
|
||||
idx :: nodeIdx(),
|
||||
parents = [] :: [nodeId()],
|
||||
type = "flat" :: nodeType(),
|
||||
owners = [] :: [ljid()],
|
||||
options = [] :: [nodeOption()]
|
||||
}).
|
||||
{
|
||||
id :: {host(), nodeId()},
|
||||
idx :: nodeIdx(),
|
||||
parents = [] :: [nodeId()],
|
||||
type = "flat" :: nodeType(),
|
||||
owners = [] :: [bareUsr()],
|
||||
options = [] :: [nodeOption()]
|
||||
}).
|
||||
|
||||
-type(pubsubNode() :: #pubsub_node{}).
|
||||
|
||||
|
||||
%%% @type pubsubState() = {pubsub_state, Id, Items, Affiliation, Subscriptions}
|
||||
%%% Id = {ljid(), nodeIdx()}
|
||||
%%% Id = {fullUsr(), nodeIdx()}
|
||||
%%% Items = [itemId()]
|
||||
%%% Affiliation = affiliation()
|
||||
%%% Subscriptions = [subscription()].
|
||||
%%% Subscriptions = [{subscription(), subId()}].
|
||||
%%%
|
||||
%%% <p>This is the format of the <tt>affiliations</tt> table. The type of the
|
||||
%%% table is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
|
||||
|
||||
-record(pubsub_state,
|
||||
{
|
||||
id :: {ljid(), nodeIdx()},
|
||||
items = [] :: [itemId()],
|
||||
affiliation = none :: affiliation(),
|
||||
subscriptions = [] :: [subscription()]
|
||||
}).
|
||||
{
|
||||
id :: {fullUsr(), nodeIdx()},
|
||||
items = [] :: [itemId()],
|
||||
affiliation = 'none' :: affiliation(),
|
||||
subscriptions = [] :: [{subscription(), subId()}]
|
||||
}).
|
||||
|
||||
-type(pubsubState() :: #pubsub_state{}).
|
||||
|
||||
|
||||
%%% @type pubsubItem() = {pubsub_item, Id, Creation, Modification, Payload}
|
||||
%%% Id = {itemId(), nodeIdx()}
|
||||
%%% Creation = {now(), ljid()}
|
||||
%%% Modification = {now(), ljid()}
|
||||
%%% Creation = {now(), bareUsr()}
|
||||
%%% Modification = {now(), fullUsr()}
|
||||
%%% Payload = payload().
|
||||
%%%
|
||||
%%% <p>This is the format of the <tt>published items</tt> table. The type of the
|
||||
%%% table is: <tt>set</tt>,<tt>disc</tt>,<tt>fragmented</tt>.</p>
|
||||
|
||||
-record(pubsub_item,
|
||||
{
|
||||
id :: {itemId(), nodeIdx()},
|
||||
creation = {unknown,unknown} :: {now(), ljid()},
|
||||
modification = {unknown,unknown} :: {now(), ljid()},
|
||||
payload = [] :: payload()
|
||||
}).
|
||||
{
|
||||
id :: {itemId(), nodeIdx()},
|
||||
creation = {unknown,unknown} :: {now(), bareUsr()},
|
||||
modification = {unknown,unknown} :: {now(), fullUsr()},
|
||||
payload = [] :: payload()
|
||||
}).
|
||||
|
||||
-type(pubsubItem() :: #pubsub_item{}).
|
||||
|
||||
|
@ -262,10 +335,10 @@
|
|||
%% table is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
|
||||
|
||||
-record(pubsub_subscription,
|
||||
{
|
||||
subid :: subId(),
|
||||
options :: [subOption()]
|
||||
}).
|
||||
{
|
||||
subid :: subId(),
|
||||
options :: [subOption()]
|
||||
}).
|
||||
|
||||
-type(pubsubSubscription() :: #pubsub_subscription{}).
|
||||
|
||||
|
@ -273,18 +346,18 @@
|
|||
%%% @type pubsubLastItem() = {pubsub_last_item, NodeId, ItemId, Creation, Payload}
|
||||
%%% NodeId = nodeIdx()
|
||||
%%% ItemId = itemId()
|
||||
%%% Creation = {now(), ljid()}
|
||||
%%% Creation = {now(), bareUsr()}
|
||||
%%% Payload = payload().
|
||||
%%%
|
||||
%% <p>This is the format of the <tt>last items</tt> table. it stores last item payload
|
||||
%% for every node</p>
|
||||
|
||||
-record(pubsub_last_item,
|
||||
{
|
||||
nodeid :: nodeIdx(),
|
||||
itemid :: itemId(),
|
||||
creation :: {now(), ljid()},
|
||||
payload :: payload()
|
||||
}).
|
||||
{
|
||||
nodeid :: nodeIdx(),
|
||||
itemid :: itemId(),
|
||||
creation :: {now(), bareUsr()},
|
||||
payload :: payload()
|
||||
}).
|
||||
|
||||
-type(pubsubLastItem() :: #pubsub_last_item{}).
|
||||
|
|
|
@ -31,35 +31,58 @@
|
|||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-export([init/3, new/1, free/2]).
|
||||
-export([
|
||||
init/3,
|
||||
new/1,
|
||||
free/2
|
||||
]).
|
||||
|
||||
|
||||
-spec(init/3 ::
|
||||
(
|
||||
Host :: string(),
|
||||
ServerHost :: string(),
|
||||
Opts :: [{Key::atom(), Value::term()}])
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
init(_Host, _ServerHost, _Opts) ->
|
||||
mnesia:create_table(pubsub_index,
|
||||
[{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, pubsub_index)}]).
|
||||
|
||||
|
||||
-spec(new/1 ::
|
||||
(
|
||||
Index::atom())
|
||||
-> Idx::integer()
|
||||
).
|
||||
|
||||
new(Index) ->
|
||||
case mnesia:read({pubsub_index, Index}) of
|
||||
[I] ->
|
||||
case I#pubsub_index.free of
|
||||
[] ->
|
||||
Id = I#pubsub_index.last + 1,
|
||||
mnesia:write(I#pubsub_index{last = Id}),
|
||||
Id;
|
||||
[Id|Free] ->
|
||||
mnesia:write(I#pubsub_index{free = Free}),
|
||||
Id
|
||||
end;
|
||||
_ ->
|
||||
mnesia:write(#pubsub_index{index = Index, last = 1, free = []}),
|
||||
1
|
||||
[#pubsub_index{free = [], last = Last} = PubsubIndex] ->
|
||||
Idx = Last + 1,
|
||||
mnesia:write(PubsubIndex#pubsub_index{last = Idx}),
|
||||
Idx;
|
||||
[#pubsub_index{free = [Idx|Free]} = PubsubIndex] ->
|
||||
mnesia:write(PubsubIndex#pubsub_index{free = Free}),
|
||||
Idx;
|
||||
_ ->
|
||||
mnesia:write(#pubsub_index{index = Index, last = 1, free = []}),
|
||||
1
|
||||
end.
|
||||
|
||||
free(Index, Id) ->
|
||||
|
||||
-spec(free/2 ::
|
||||
(
|
||||
Index :: atom(),
|
||||
Idx :: integer())
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
free(Index, Idx) ->
|
||||
case mnesia:read({pubsub_index, Index}) of
|
||||
[I] ->
|
||||
Free = I#pubsub_index.free,
|
||||
mnesia:write(I#pubsub_index{free = [Id|Free]});
|
||||
_ ->
|
||||
ok
|
||||
[#pubsub_index{free = Free} = PubsubIndex] ->
|
||||
mnesia:write(PubsubIndex#pubsub_index{free = [Idx|Free]});
|
||||
_ -> ok
|
||||
end.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--- mod_pubsub.erl 2010-09-20 15:56:56.000000000 +0200
|
||||
+++ mod_pubsub_odbc.erl 2010-09-20 16:50:49.000000000 +0200
|
||||
--- mod_pubsub.erl 2010-09-23 10:43:43.000000000 +0200
|
||||
+++ mod_pubsub_odbc.erl 2010-09-29 11:46:22.000000000 +0200
|
||||
@@ -42,7 +42,7 @@
|
||||
%%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see
|
||||
%%% XEP-0060 section 12.18.
|
||||
|
|
|
@ -24,28 +24,32 @@
|
|||
-author("bjc@kublai.com").
|
||||
|
||||
%% API
|
||||
-export([init/0,
|
||||
-export([
|
||||
init/0,
|
||||
subscribe_node/3,
|
||||
unsubscribe_node/3,
|
||||
get_subscription/3,
|
||||
set_subscription/4,
|
||||
get_options_xform/2,
|
||||
parse_options_xform/1]).
|
||||
parse_options_xform/1
|
||||
]).
|
||||
|
||||
% Internal function also exported for use in transactional bloc from pubsub plugins
|
||||
-export([add_subscription/3,
|
||||
% Internal function also exported for use in transactional bloc from pubsub plugins
|
||||
-export([
|
||||
add_subscription/3,
|
||||
delete_subscription/3,
|
||||
read_subscription/3,
|
||||
write_subscription/4]).
|
||||
write_subscription/4
|
||||
]).
|
||||
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-define(PUBSUB_DELIVER, "pubsub#deliver").
|
||||
-define(PUBSUB_DIGEST, "pubsub#digest").
|
||||
-define(PUBSUB_DELIVER, "pubsub#deliver").
|
||||
-define(PUBSUB_DIGEST, "pubsub#digest").
|
||||
-define(PUBSUB_DIGEST_FREQUENCY, "pubsub#digest_frequency").
|
||||
-define(PUBSUB_EXPIRE, "pubsub#expire").
|
||||
-define(PUBSUB_EXPIRE, "pubsub#expire").
|
||||
-define(PUBSUB_INCLUDE_BODY, "pubsub#include_body").
|
||||
-define(PUBSUB_SHOW_VALUES, "pubsub#show-values").
|
||||
-define(PUBSUB_SHOW_VALUES, "pubsub#show-values").
|
||||
-define(PUBSUB_SUBSCRIPTION_TYPE, "pubsub#subscription_type").
|
||||
-define(PUBSUB_SUBSCRIPTION_DEPTH, "pubsub#subscription_depth").
|
||||
|
||||
|
@ -54,11 +58,11 @@
|
|||
-define(DIGEST_LABEL,
|
||||
"Whether an entity wants to receive digests (aggregations) of notifications or all notifications individually").
|
||||
-define(DIGEST_FREQUENCY_LABEL,
|
||||
"The minimum number of milliseconds between sending any two notification digests").
|
||||
"The minimum number of milliseconds between sending any two notification digests").
|
||||
-define(EXPIRE_LABEL,
|
||||
"The DateTime at which a leased subscription will end or has ended").
|
||||
-define(INCLUDE_BODY_LABEL,
|
||||
"Whether an entity wants to receive an XMPP message body in addition to the payload format").
|
||||
"Whether an entity wants to receive an XMPP message body in addition to the payload format").
|
||||
-define(SHOW_VALUES_LABEL,
|
||||
"The presence states for which an entity wants to receive notifications").
|
||||
-define(SUBSCRIPTION_TYPE_LABEL,
|
||||
|
@ -85,113 +89,194 @@
|
|||
%%====================================================================
|
||||
%% API
|
||||
%%====================================================================
|
||||
-spec(init/0 :: () -> 'ok').
|
||||
|
||||
init() ->
|
||||
ok = create_table().
|
||||
|
||||
subscribe_node(JID, NodeId, Options) ->
|
||||
try mnesia:sync_dirty(fun add_subscription/3,
|
||||
[JID, NodeId, Options]) of
|
||||
{error, Error} -> {error, Error};
|
||||
Result -> {result, Result}
|
||||
catch
|
||||
Error -> Error
|
||||
end.
|
||||
-spec(subscribe_node/3 ::
|
||||
(
|
||||
Entity :: jidEntity() | fullUsr(),
|
||||
NodeIdx :: nodeIdx(),
|
||||
Options :: [nodeOption()])
|
||||
-> {'result', SubId::subId()} | {'error', _}
|
||||
).
|
||||
|
||||
unsubscribe_node(JID, NodeId, SubId) ->
|
||||
try mnesia:sync_dirty(fun delete_subscription/3,
|
||||
[JID, NodeId, SubId]) of
|
||||
subscribe_node(#jid{node = U, domain = S, resource = R}, NodeIdx, Options) ->
|
||||
subscribe_node({U,S,R}, NodeIdx, Options);
|
||||
subscribe_node(Entity, NodeIdx, Options) ->
|
||||
try mnesia:sync_dirty(fun add_subscription/3, [Entity, NodeIdx, Options]) of
|
||||
{error, Error} -> {error, Error};
|
||||
Result -> {result, Result}
|
||||
Result -> {result, Result}
|
||||
catch
|
||||
Error -> Error
|
||||
end.
|
||||
|
||||
get_subscription(JID, NodeId, SubId) ->
|
||||
try mnesia:sync_dirty(fun read_subscription/3,
|
||||
[JID, NodeId, SubId]) of
|
||||
|
||||
-spec(unsubscribe_node/3 ::
|
||||
(
|
||||
JID :: jidEntity(),
|
||||
NodeIdx :: nodeIdx(),
|
||||
SubId :: subId())
|
||||
-> {'result','ok'} | {'error', _}
|
||||
).
|
||||
|
||||
unsubscribe_node(#jid{node = U, domain = S, resource = R} = _JID, NodeIdx, SubId) ->
|
||||
try mnesia:sync_dirty(fun delete_subscription/3, [{U,S,R}, NodeIdx, SubId]) of
|
||||
{error, Error} -> {error, Error};
|
||||
Result -> {result, Result}
|
||||
Result -> {result, Result}
|
||||
catch
|
||||
Error -> Error
|
||||
end.
|
||||
|
||||
set_subscription(JID, NodeId, SubId, Options) ->
|
||||
try mnesia:sync_dirty(fun write_subscription/4,
|
||||
[JID, NodeId, SubId, Options]) of
|
||||
|
||||
-spec(get_subscription/3 ::
|
||||
(
|
||||
JID :: jidEntity(),
|
||||
NodeIdx :: nodeIdx(),
|
||||
SubId :: subId())
|
||||
-> {'result', pubsubSubscription()} | {'error', _}
|
||||
).
|
||||
|
||||
get_subscription(#jid{node = U, domain = S, resource = R} = _JID, NodeIdx, SubId) ->
|
||||
try mnesia:sync_dirty(fun read_subscription/3, [{U,S,R}, NodeIdx, SubId]) of
|
||||
{error, Error} -> {error, Error};
|
||||
Result -> {result, Result}
|
||||
Subscription -> {result, Subscription}
|
||||
catch
|
||||
Error -> Error
|
||||
end.
|
||||
|
||||
|
||||
-spec(set_subscription/4 ::
|
||||
(
|
||||
JID :: jidEntity(),
|
||||
NodeIdx :: nodeIdx(),
|
||||
SubId :: subId(),
|
||||
Options :: [nodeOption()])
|
||||
-> {'result', 'ok'} | {'error', _}
|
||||
).
|
||||
|
||||
set_subscription(#jid{node = U, domain = S, resource = R} = _JID, NodeIdx, SubId, Options) ->
|
||||
try mnesia:sync_dirty(fun write_subscription/4, [{U,S,R}, NodeIdx, SubId, Options]) of
|
||||
{error, Error} -> {error, Error};
|
||||
Result -> {result, Result}
|
||||
catch
|
||||
Error -> Error
|
||||
end.
|
||||
|
||||
|
||||
%% TODO : check input type data
|
||||
get_options_xform(Lang, Options) ->
|
||||
Keys = [deliver, digest, digest_frequency, expire, include_body, show_values, subscription_type, subscription_depth],
|
||||
XFields = [get_option_xfield(Lang, Key, Options) || Key <- Keys],
|
||||
|
||||
{result, #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children =
|
||||
[#xmlel{ns = ?NS_DATA_FORMS,
|
||||
name = 'field',
|
||||
attrs = [?XMLATTR('var', <<"FORM_TYPE">>), ?XMLATTR('type', <<"hidden">>)],
|
||||
children = [#xmlel{ns = ?NS_DATA_FORMS,
|
||||
name = 'value',
|
||||
children = [?XMLCDATA(?NS_PUBSUB_SUBSCRIBE_OPTIONS_s)]}]}] ++ XFields}}.
|
||||
{result, #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs = [?XMLATTR('type', <<"form">>)], children =
|
||||
[#xmlel{ns = ?NS_DATA_FORMS,
|
||||
name = 'field',
|
||||
attrs = [?XMLATTR('var', <<"FORM_TYPE">>), ?XMLATTR('type', <<"hidden">>)],
|
||||
children = [#xmlel{ns = ?NS_DATA_FORMS,
|
||||
name = 'value',
|
||||
children = [?XMLCDATA(?NS_PUBSUB_SUBSCRIBE_OPTIONS_s)]}]}] ++ XFields}}.
|
||||
|
||||
%% TODO : check input type data
|
||||
parse_options_xform(XFields) ->
|
||||
case XFields of
|
||||
[] -> {result, []};
|
||||
_ -> case exmpp_xml:remove_cdata_from_list(XFields) of
|
||||
[] -> {result, []};
|
||||
[#xmlel{name = 'x'} = XEl] ->
|
||||
case jlib:parse_xdata_submit(XEl) of
|
||||
XData when is_list(XData) ->
|
||||
case set_xoption(XData, []) of
|
||||
Opts when is_list(Opts) -> {result, Opts};
|
||||
Other -> Other
|
||||
end;
|
||||
Other ->
|
||||
Other
|
||||
end;
|
||||
Other ->
|
||||
Other
|
||||
end
|
||||
[] -> {result, []};
|
||||
_ -> case exmpp_xml:remove_cdata_from_list(XFields) of
|
||||
[] -> {result, []};
|
||||
[#xmlel{name = 'x'} = XEl] ->
|
||||
case jlib:parse_xdata_submit(XEl) of
|
||||
XData when is_list(XData) ->
|
||||
case set_xoption(XData, []) of
|
||||
Opts when is_list(Opts) -> {result, Opts};
|
||||
Other -> Other
|
||||
end;
|
||||
Other ->
|
||||
Other
|
||||
end;
|
||||
Other ->
|
||||
Other
|
||||
end
|
||||
end.
|
||||
|
||||
%%====================================================================
|
||||
%% Internal functions
|
||||
%%====================================================================
|
||||
-spec(create_table/0 :: () -> 'ok').
|
||||
|
||||
create_table() ->
|
||||
case mnesia:create_table(pubsub_subscription,
|
||||
[{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, pubsub_subscription)},
|
||||
{type, set}]) of
|
||||
{atomic, ok} -> ok;
|
||||
{type, set}])
|
||||
of
|
||||
{atomic, ok} -> ok;
|
||||
{aborted, {already_exists, _}} -> ok;
|
||||
Other -> Other
|
||||
Other -> Other
|
||||
end.
|
||||
|
||||
add_subscription(_JID, _NodeId, Options) ->
|
||||
-spec(add_subscription/3 ::
|
||||
(
|
||||
Entity :: fullUsr(),
|
||||
NodeIdx :: nodeIdx(),
|
||||
Options :: [nodeOption()])
|
||||
-> SubId::subId()
|
||||
).
|
||||
|
||||
add_subscription(_Entity, _NodeIdx, Options) ->
|
||||
SubId = make_subid(),
|
||||
mnesia:write(#pubsub_subscription{subid = SubId, options = Options}),
|
||||
SubId.
|
||||
|
||||
delete_subscription(_JID, _NodeId, SubId) ->
|
||||
|
||||
-spec(delete_subscription/3 ::
|
||||
(
|
||||
Entity :: fullUsr(),
|
||||
NodeIdx :: nodeIdx(),
|
||||
SubId :: subId())
|
||||
-> 'ok'
|
||||
).
|
||||
|
||||
delete_subscription(_Entity, _NodeIdx, SubId) ->
|
||||
mnesia:delete({pubsub_subscription, SubId}).
|
||||
|
||||
read_subscription(_JID, _NodeId, SubId) ->
|
||||
|
||||
-spec(read_subscription/3 ::
|
||||
(
|
||||
Entity :: fullUsr(),
|
||||
NodeIdx :: nodeIdx(),
|
||||
SubId :: subId())
|
||||
-> pubsubSubscription() | {'error', 'notfound'}
|
||||
).
|
||||
|
||||
read_subscription(_Entity, _NodeIdx, SubId) ->
|
||||
case mnesia:read({pubsub_subscription, SubId}) of
|
||||
[Sub] -> Sub;
|
||||
_ -> {error, notfound}
|
||||
[Subscription] -> Subscription;
|
||||
_ -> {'error', 'notfound'}
|
||||
end.
|
||||
|
||||
write_subscription(JID, NodeId, SubId, Options) ->
|
||||
case read_subscription(JID, NodeId, SubId) of
|
||||
{error, notfound} -> {error, notfound};
|
||||
Sub -> mnesia:write(Sub#pubsub_subscription{options = Options})
|
||||
|
||||
-spec(write_subscription/4 ::
|
||||
(
|
||||
Entity :: fullUsr(),
|
||||
NodeIdx :: nodeIdx(),
|
||||
SubId :: subId(),
|
||||
Options :: [nodeOption()])
|
||||
-> 'ok' | {'error', 'notfound'}
|
||||
).
|
||||
|
||||
write_subscription(Entity, NodeIdx, SubId, Options) ->
|
||||
case read_subscription(Entity, NodeIdx, SubId) of
|
||||
{error, 'notfound'} -> {error, 'notfound'};
|
||||
Subscription -> mnesia:write(Subscription#pubsub_subscription{options = Options})
|
||||
end.
|
||||
|
||||
|
||||
-spec(make_subid/0 :: () -> SubId::subId()).
|
||||
|
||||
make_subid() ->
|
||||
{T1, T2, T3} = now(),
|
||||
lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3])).
|
||||
list_to_binary(lists:flatten(io_lib:fwrite("~.16B~.16B~.16B", [T1, T2, T3]))).
|
||||
|
||||
%%
|
||||
%% Subscription XForm processing.
|
||||
|
@ -199,6 +284,7 @@ make_subid() ->
|
|||
|
||||
%% Return processed options, with types converted and so forth, using
|
||||
%% Opts as defaults.
|
||||
%% TODO : check input type data
|
||||
set_xoption([], Opts) ->
|
||||
Opts;
|
||||
set_xoption([{Var, Value} | T], Opts) ->
|
||||
|
@ -211,33 +297,36 @@ set_xoption([{Var, Value} | T], Opts) ->
|
|||
end,
|
||||
set_xoption(T, NewOpts).
|
||||
|
||||
|
||||
%% Return the options list's key for an XForm var.
|
||||
var_xfield(?PUBSUB_DELIVER) -> deliver;
|
||||
var_xfield(?PUBSUB_DIGEST) -> digest;
|
||||
var_xfield(?PUBSUB_DIGEST_FREQUENCY) -> digest_frequency;
|
||||
var_xfield(?PUBSUB_EXPIRE) -> expire;
|
||||
var_xfield(?PUBSUB_INCLUDE_BODY) -> include_body;
|
||||
var_xfield(?PUBSUB_SHOW_VALUES) -> show_values;
|
||||
var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) -> subscription_type;
|
||||
var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) -> subscription_depth;
|
||||
var_xfield(_) -> {error, badarg}.
|
||||
var_xfield(?PUBSUB_DELIVER) -> 'deliver';
|
||||
var_xfield(?PUBSUB_DIGEST) -> 'digest';
|
||||
var_xfield(?PUBSUB_DIGEST_FREQUENCY) -> 'digest_frequency';
|
||||
var_xfield(?PUBSUB_EXPIRE) -> 'expire';
|
||||
var_xfield(?PUBSUB_INCLUDE_BODY) -> 'include_body';
|
||||
var_xfield(?PUBSUB_SHOW_VALUES) -> 'show_values';
|
||||
var_xfield(?PUBSUB_SUBSCRIPTION_TYPE) -> 'subscription_type';
|
||||
var_xfield(?PUBSUB_SUBSCRIPTION_DEPTH) -> 'subscription_depth';
|
||||
var_xfield(_) -> {error, 'badarg'}.
|
||||
|
||||
|
||||
%% Convert Values for option list's Key.
|
||||
val_xfield(deliver, [Val]) -> xopt_to_bool(Val);
|
||||
val_xfield(digest, [Val]) -> xopt_to_bool(Val);
|
||||
val_xfield(digest_frequency, [Val]) -> list_to_integer(Val);
|
||||
val_xfield(expire, [Val]) -> jlib:datetime_string_to_timestamp(Val);
|
||||
val_xfield(include_body, [Val]) -> xopt_to_bool(Val);
|
||||
val_xfield(show_values, Vals) -> Vals;
|
||||
val_xfield(subscription_type, ["items"]) -> items;
|
||||
val_xfield(subscription_type, ["nodes"]) -> nodes;
|
||||
val_xfield(subscription_depth, ["all"]) -> all;
|
||||
val_xfield(subscription_depth, [Depth]) ->
|
||||
val_xfield('deliver', [Val]) -> xopt_to_bool(Val);
|
||||
val_xfield('digest', [Val]) -> xopt_to_bool(Val);
|
||||
val_xfield('digest_frequency', [Val]) -> list_to_integer(Val);
|
||||
val_xfield('expire', [Val]) -> jlib:datetime_string_to_timestamp(Val);
|
||||
val_xfield('include_body', [Val]) -> xopt_to_bool(Val);
|
||||
val_xfield('show_values', Vals) -> Vals;
|
||||
val_xfield('subscription_type', ["items"]) -> items;
|
||||
val_xfield('subscription_type', ["nodes"]) -> nodes;
|
||||
val_xfield('subscription_depth', ["all"]) -> all;
|
||||
val_xfield('subscription_depth', [Depth]) ->
|
||||
case catch list_to_integer(Depth) of
|
||||
N when is_integer(N) -> N;
|
||||
_ -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'not-acceptable')}
|
||||
Integer when is_integer(Integer) -> Integer;
|
||||
_ -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'not-acceptable')}
|
||||
end.
|
||||
|
||||
|
||||
%% Convert XForm booleans to Erlang booleans.
|
||||
xopt_to_bool("0") -> false;
|
||||
xopt_to_bool("1") -> true;
|
||||
|
@ -247,6 +336,7 @@ xopt_to_bool(_) -> {error, exmpp_stanza:error(?NS_JABBER_CLIENT, 'not-acce
|
|||
|
||||
%% Return a field for an XForm for Key, with data filled in, if
|
||||
%% applicable, from Options.
|
||||
%% TODO : check input type data
|
||||
get_option_xfield(Lang, Key, Options) ->
|
||||
Var = xfield_var(Key),
|
||||
Label = xfield_label(Key),
|
||||
|
@ -262,73 +352,76 @@ get_option_xfield(Lang, Key, Options) ->
|
|||
attrs = [?XMLATTR('var', Var), ?XMLATTR('type', Type), ?XMLATTR('label', translate:translate(Lang, Label))],
|
||||
children = OptEls ++ Vals}.
|
||||
|
||||
%% TODO : check input type data
|
||||
type_and_options({Type, Options}, Lang) ->
|
||||
{Type, [tr_xfield_options(O, Lang) || O <- Options]};
|
||||
type_and_options(Type, _Lang) ->
|
||||
{Type, []}.
|
||||
|
||||
%% TODO : check input type data
|
||||
tr_xfield_options({Value, Label}, Lang) ->
|
||||
#xmlel{ns = ?NS_DATA_FORMS,
|
||||
name = 'option',
|
||||
attrs = [?XMLATTR('label', translate:translate(Lang, Label))],
|
||||
children = [#xmlel{ns = ?NS_DATA_FORMS,
|
||||
name = 'value',
|
||||
children = [?XMLCDATA(Value)]}]}.
|
||||
name = 'option',
|
||||
attrs = [?XMLATTR('label', translate:translate(Lang, Label))],
|
||||
children = [#xmlel{ns = ?NS_DATA_FORMS,
|
||||
name = 'value',
|
||||
children = [?XMLCDATA(Value)]}]}.
|
||||
|
||||
%% TODO : check input type data
|
||||
tr_xfield_values(Value) ->
|
||||
#xmlel{ns = ?NS_DATA_FORMS, name ='value', children = [?XMLCDATA(Value)]}.
|
||||
|
||||
%% Return the XForm variable name for a subscription option key.
|
||||
xfield_var(deliver) -> ?PUBSUB_DELIVER;
|
||||
xfield_var(digest) -> ?PUBSUB_DIGEST;
|
||||
xfield_var(digest_frequency) -> ?PUBSUB_DIGEST_FREQUENCY;
|
||||
xfield_var(expire) -> ?PUBSUB_EXPIRE;
|
||||
xfield_var(include_body) -> ?PUBSUB_INCLUDE_BODY;
|
||||
xfield_var(show_values) -> ?PUBSUB_SHOW_VALUES;
|
||||
xfield_var(subscription_type) -> ?PUBSUB_SUBSCRIPTION_TYPE;
|
||||
xfield_var(subscription_depth) -> ?PUBSUB_SUBSCRIPTION_DEPTH.
|
||||
xfield_var('deliver') -> ?PUBSUB_DELIVER;
|
||||
xfield_var('digest') -> ?PUBSUB_DIGEST;
|
||||
xfield_var('digest_frequency') -> ?PUBSUB_DIGEST_FREQUENCY;
|
||||
xfield_var('expire') -> ?PUBSUB_EXPIRE;
|
||||
xfield_var('include_body') -> ?PUBSUB_INCLUDE_BODY;
|
||||
xfield_var('show_values') -> ?PUBSUB_SHOW_VALUES;
|
||||
xfield_var('subscription_type') -> ?PUBSUB_SUBSCRIPTION_TYPE;
|
||||
xfield_var('subscription_depth') -> ?PUBSUB_SUBSCRIPTION_DEPTH.
|
||||
|
||||
%% Return the XForm variable type for a subscription option key.
|
||||
xfield_type(deliver) -> "boolean";
|
||||
xfield_type(digest) -> "boolean";
|
||||
xfield_type(digest_frequency) -> "text-single";
|
||||
xfield_type(expire) -> "text-single";
|
||||
xfield_type(include_body) -> "boolean";
|
||||
xfield_type(show_values) ->
|
||||
xfield_type('deliver') -> "boolean";
|
||||
xfield_type('digest') -> "boolean";
|
||||
xfield_type('digest_frequency') -> "text-single";
|
||||
xfield_type('expire') -> "text-single";
|
||||
xfield_type('include_body') -> "boolean";
|
||||
xfield_type('show_values') ->
|
||||
{"list-multi", [{"away", ?SHOW_VALUE_AWAY_LABEL},
|
||||
{"chat", ?SHOW_VALUE_CHAT_LABEL},
|
||||
{"dnd", ?SHOW_VALUE_DND_LABEL},
|
||||
{"online", ?SHOW_VALUE_ONLINE_LABEL},
|
||||
{"xa", ?SHOW_VALUE_XA_LABEL}]};
|
||||
xfield_type(subscription_type) ->
|
||||
xfield_type(subscription_type) ->
|
||||
{"list-single", [{"items", ?SUBSCRIPTION_TYPE_VALUE_ITEMS_LABEL},
|
||||
{"nodes", ?SUBSCRIPTION_TYPE_VALUE_NODES_LABEL}]};
|
||||
xfield_type(subscription_depth) ->
|
||||
{"list-single", [{"1", ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL},
|
||||
{"list-single", [{"1", ?SUBSCRIPTION_DEPTH_VALUE_ONE_LABEL},
|
||||
{"all", ?SUBSCRIPTION_DEPTH_VALUE_ALL_LABEL}]}.
|
||||
|
||||
%% Return the XForm variable label for a subscription option key.
|
||||
xfield_label(deliver) -> ?DELIVER_LABEL;
|
||||
xfield_label(digest) -> ?DIGEST_LABEL;
|
||||
xfield_label(digest_frequency) -> ?DIGEST_FREQUENCY_LABEL;
|
||||
xfield_label(expire) -> ?EXPIRE_LABEL;
|
||||
xfield_label(include_body) -> ?INCLUDE_BODY_LABEL;
|
||||
xfield_label(show_values) -> ?SHOW_VALUES_LABEL;
|
||||
xfield_label(subscription_type) -> ?SUBSCRIPTION_TYPE_LABEL;
|
||||
xfield_label(subscription_depth) -> ?SUBSCRIPTION_DEPTH_LABEL.
|
||||
xfield_label('deliver') -> ?DELIVER_LABEL;
|
||||
xfield_label('digest') -> ?DIGEST_LABEL;
|
||||
xfield_label('digest_frequency') -> ?DIGEST_FREQUENCY_LABEL;
|
||||
xfield_label('expire') -> ?EXPIRE_LABEL;
|
||||
xfield_label('include_body') -> ?INCLUDE_BODY_LABEL;
|
||||
xfield_label('show_values') -> ?SHOW_VALUES_LABEL;
|
||||
xfield_label('subscription_type') -> ?SUBSCRIPTION_TYPE_LABEL;
|
||||
xfield_label('subscription_depth') -> ?SUBSCRIPTION_DEPTH_LABEL.
|
||||
|
||||
%% Return the XForm value for a subscription option key.
|
||||
xfield_val(deliver, Val) -> [bool_to_xopt(Val)];
|
||||
xfield_val(digest, Val) -> [bool_to_xopt(Val)];
|
||||
xfield_val(digest_frequency, Val) -> [integer_to_list(Val)];
|
||||
xfield_val(expire, Val) -> [jlib:now_to_utc_string(Val)];
|
||||
xfield_val(include_body, Val) -> [bool_to_xopt(Val)];
|
||||
xfield_val(show_values, Val) -> Val;
|
||||
xfield_val(subscription_type, items) -> ["items"];
|
||||
xfield_val(subscription_type, nodes) -> ["nodes"];
|
||||
xfield_val(subscription_depth, all) -> ["all"];
|
||||
xfield_val(subscription_depth, N) -> [integer_to_list(N)].
|
||||
xfield_val('deliver', Val) -> [bool_to_xopt(Val)];
|
||||
xfield_val('digest', Val) -> [bool_to_xopt(Val)];
|
||||
xfield_val('digest_frequency', Val) -> [integer_to_list(Val)];
|
||||
xfield_val('expire', Val) -> [jlib:now_to_utc_string(Val)];
|
||||
xfield_val('include_body', Val) -> [bool_to_xopt(Val)];
|
||||
xfield_val('show_values', Val) -> Val;
|
||||
xfield_val('subscription_type', 'items') -> ["items"];
|
||||
xfield_val('subscription_type', 'nodes') -> ["nodes"];
|
||||
xfield_val('subscription_depth', 'all') -> ["all"];
|
||||
xfield_val('subscription_depth', Depth) -> [integer_to_list(Depth)].
|
||||
|
||||
%% Convert erlang booleans to XForms.
|
||||
bool_to_xopt(false) -> "false";
|
||||
bool_to_xopt(true) -> "true".
|
||||
bool_to_xopt('false') -> "false";
|
||||
bool_to_xopt('true') -> "true".
|
||||
|
|
Loading…
Reference in New Issue