Support for XEP-0411: Bookmarks Conversion
This commit is contained in:
parent
87f8355908
commit
1cdca1ab99
|
@ -25,7 +25,7 @@
|
||||||
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", "9b25543cf1200e3b216996598771962461ea51c8"}},
|
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", "9b25543cf1200e3b216996598771962461ea51c8"}},
|
||||||
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.14"}}},
|
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.14"}}},
|
||||||
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.34"}}},
|
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.34"}}},
|
||||||
{xmpp, ".*", {git, "https://github.com/processone/xmpp", "032548195547c68e77c7d89f51e3fbe0522fc218"}},
|
{xmpp, ".*", {git, "https://github.com/processone/xmpp", "ff6d9b5"}},
|
||||||
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.17"}}},
|
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.17"}}},
|
||||||
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.8"}}},
|
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.8"}}},
|
||||||
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.3"}}},
|
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.3"}}},
|
||||||
|
|
|
@ -111,7 +111,6 @@ process_xdb(User, Server,
|
||||||
xdb_data(_User, _Server, {xmlcdata, _CData}) -> ok;
|
xdb_data(_User, _Server, {xmlcdata, _CData}) -> ok;
|
||||||
xdb_data(User, Server, #xmlel{attrs = Attrs} = El) ->
|
xdb_data(User, Server, #xmlel{attrs = Attrs} = El) ->
|
||||||
From = jid:make(User, Server),
|
From = jid:make(User, Server),
|
||||||
LUser = From#jid.luser,
|
|
||||||
LServer = From#jid.lserver,
|
LServer = From#jid.lserver,
|
||||||
case fxml:get_attr_s(<<"xmlns">>, Attrs) of
|
case fxml:get_attr_s(<<"xmlns">>, Attrs) of
|
||||||
?NS_AUTH ->
|
?NS_AUTH ->
|
||||||
|
@ -142,7 +141,7 @@ xdb_data(User, Server, #xmlel{attrs = Attrs} = El) ->
|
||||||
(_) -> true
|
(_) -> true
|
||||||
end, Attrs),
|
end, Attrs),
|
||||||
catch mod_private:set_data(
|
catch mod_private:set_data(
|
||||||
LUser, LServer,
|
From,
|
||||||
[{XMLNS, El#xmlel{attrs = NewAttrs}}]);
|
[{XMLNS, El#xmlel{attrs = NewAttrs}}]);
|
||||||
_ ->
|
_ ->
|
||||||
?DEBUG("jd2ejd: Unknown namespace \"~s\"~n", [XMLNS])
|
?DEBUG("jd2ejd: Unknown namespace \"~s\"~n", [XMLNS])
|
||||||
|
|
|
@ -1388,8 +1388,8 @@ private_set(Username, Host, ElementString) ->
|
||||||
|
|
||||||
private_set2(Username, Host, Xml) ->
|
private_set2(Username, Host, Xml) ->
|
||||||
NS = fxml:get_tag_attr_s(<<"xmlns">>, Xml),
|
NS = fxml:get_tag_attr_s(<<"xmlns">>, Xml),
|
||||||
mod_private:set_data(jid:nodeprep(Username), jid:nameprep(Host),
|
JID = jid:make(Username, Host),
|
||||||
[{NS, Xml}]).
|
mod_private:set_data(JID, [{NS, Xml}]).
|
||||||
|
|
||||||
%%%
|
%%%
|
||||||
%%% Shared Roster Groups
|
%%% Shared Roster Groups
|
||||||
|
|
|
@ -28,13 +28,14 @@
|
||||||
-author('alexey@process-one.net').
|
-author('alexey@process-one.net').
|
||||||
|
|
||||||
-protocol({xep, 49, '1.2'}).
|
-protocol({xep, 49, '1.2'}).
|
||||||
|
-protocol({xep, 411, '0.2.0'}).
|
||||||
|
|
||||||
-behaviour(gen_mod).
|
-behaviour(gen_mod).
|
||||||
|
|
||||||
-export([start/2, stop/1, reload/3, process_sm_iq/1, import_info/0,
|
-export([start/2, stop/1, reload/3, process_sm_iq/1, import_info/0,
|
||||||
remove_user/2, get_data/2, get_data/3, export/1,
|
remove_user/2, get_data/2, get_data/3, export/1,
|
||||||
import/5, import_start/2, mod_opt_type/1, set_data/3,
|
import/5, import_start/2, mod_opt_type/1, set_data/2,
|
||||||
mod_options/1, depends/2]).
|
mod_options/1, depends/2, get_sm_features/5, pubsub_publish_item/6]).
|
||||||
|
|
||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
-include("xmpp.hrl").
|
-include("xmpp.hrl").
|
||||||
|
@ -57,16 +58,16 @@ start(Host, Opts) ->
|
||||||
Mod = gen_mod:db_mod(Host, Opts, ?MODULE),
|
Mod = gen_mod:db_mod(Host, Opts, ?MODULE),
|
||||||
Mod:init(Host, Opts),
|
Mod:init(Host, Opts),
|
||||||
init_cache(Mod, Host, Opts),
|
init_cache(Mod, Host, Opts),
|
||||||
ejabberd_hooks:add(remove_user, Host, ?MODULE,
|
ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50),
|
||||||
remove_user, 50),
|
ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
|
||||||
gen_iq_handler:add_iq_handler(ejabberd_sm, Host,
|
ejabberd_hooks:add(pubsub_publish_item, Host, ?MODULE, pubsub_publish_item, 50),
|
||||||
?NS_PRIVATE, ?MODULE, process_sm_iq).
|
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE, ?MODULE, process_sm_iq).
|
||||||
|
|
||||||
stop(Host) ->
|
stop(Host) ->
|
||||||
ejabberd_hooks:delete(remove_user, Host, ?MODULE,
|
ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50),
|
||||||
remove_user, 50),
|
ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
|
||||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host,
|
ejabberd_hooks:delete(pubsub_publish_item, Host, ?MODULE, pubsub_publish_item, 50),
|
||||||
?NS_PRIVATE).
|
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PRIVATE).
|
||||||
|
|
||||||
reload(Host, NewOpts, OldOpts) ->
|
reload(Host, NewOpts, OldOpts) ->
|
||||||
NewMod = gen_mod:db_mod(Host, NewOpts, ?MODULE),
|
NewMod = gen_mod:db_mod(Host, NewOpts, ?MODULE),
|
||||||
|
@ -78,9 +79,41 @@ reload(Host, NewOpts, OldOpts) ->
|
||||||
end,
|
end,
|
||||||
init_cache(NewMod, Host, NewOpts).
|
init_cache(NewMod, Host, NewOpts).
|
||||||
|
|
||||||
|
depends(_Host, _Opts) ->
|
||||||
|
[{mod_pubsub, soft}].
|
||||||
|
|
||||||
|
mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
||||||
|
mod_opt_type(O) when O == cache_life_time; O == cache_size ->
|
||||||
|
fun (I) when is_integer(I), I > 0 -> I;
|
||||||
|
(infinity) -> infinity
|
||||||
|
end;
|
||||||
|
mod_opt_type(O) when O == use_cache; O == cache_missed ->
|
||||||
|
fun (B) when is_boolean(B) -> B end.
|
||||||
|
|
||||||
|
mod_options(Host) ->
|
||||||
|
[{db_type, ejabberd_config:default_db(Host, ?MODULE)},
|
||||||
|
{use_cache, ejabberd_config:use_cache(Host)},
|
||||||
|
{cache_size, ejabberd_config:cache_size(Host)},
|
||||||
|
{cache_missed, ejabberd_config:cache_missed(Host)},
|
||||||
|
{cache_life_time, ejabberd_config:cache_life_time(Host)}].
|
||||||
|
|
||||||
|
-spec get_sm_features({error, stanza_error()} | empty | {result, [binary()]},
|
||||||
|
jid(), jid(), binary(), binary()) ->
|
||||||
|
{error, stanza_error()} | empty | {result, [binary()]}.
|
||||||
|
get_sm_features({error, _Error} = Acc, _From, _To, _Node, _Lang) ->
|
||||||
|
Acc;
|
||||||
|
get_sm_features(Acc, _From, _To, <<"">>, _Lang) ->
|
||||||
|
{result, [?NS_BOOKMARKS_CONVERSION_0 |
|
||||||
|
case Acc of
|
||||||
|
{result, Features} -> Features;
|
||||||
|
empty -> []
|
||||||
|
end]};
|
||||||
|
get_sm_features(Acc, _From, _To, _Node, _Lang) ->
|
||||||
|
Acc.
|
||||||
|
|
||||||
-spec process_sm_iq(iq()) -> iq().
|
-spec process_sm_iq(iq()) -> iq().
|
||||||
process_sm_iq(#iq{type = Type, lang = Lang,
|
process_sm_iq(#iq{type = Type, lang = Lang,
|
||||||
from = #jid{luser = LUser, lserver = LServer},
|
from = #jid{luser = LUser, lserver = LServer} = From,
|
||||||
to = #jid{luser = LUser, lserver = LServer},
|
to = #jid{luser = LUser, lserver = LServer},
|
||||||
sub_els = [#private{sub_els = Els0}]} = IQ) ->
|
sub_els = [#private{sub_els = Els0}]} = IQ) ->
|
||||||
case filter_xmlels(Els0) of
|
case filter_xmlels(Els0) of
|
||||||
|
@ -88,9 +121,11 @@ process_sm_iq(#iq{type = Type, lang = Lang,
|
||||||
Txt = <<"No private data found in this query">>,
|
Txt = <<"No private data found in this query">>,
|
||||||
xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang));
|
xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang));
|
||||||
Data when Type == set ->
|
Data when Type == set ->
|
||||||
case set_data(LUser, LServer, Data) of
|
case set_data(From, Data) of
|
||||||
ok ->
|
ok ->
|
||||||
xmpp:make_iq_result(IQ);
|
xmpp:make_iq_result(IQ);
|
||||||
|
{error, #stanza_error{} = Err} ->
|
||||||
|
xmpp:make_error(IQ, Err);
|
||||||
{error, _} ->
|
{error, _} ->
|
||||||
Txt = <<"Database failure">>,
|
Txt = <<"Database failure">>,
|
||||||
Err = xmpp:err_internal_server_error(Txt, Lang),
|
Err = xmpp:err_internal_server_error(Txt, Lang),
|
||||||
|
@ -120,12 +155,21 @@ filter_xmlels(Els) ->
|
||||||
end
|
end
|
||||||
end, Els).
|
end, Els).
|
||||||
|
|
||||||
-spec set_data(binary(), binary(), [{binary(), xmlel()}]) -> ok | {error, _}.
|
-spec set_data(jid(), [{binary(), xmlel()}]) -> ok | {error, _}.
|
||||||
set_data(LUser, LServer, Data) ->
|
set_data(JID, Data) ->
|
||||||
|
set_data(JID, Data, true).
|
||||||
|
|
||||||
|
-spec set_data(jid(), [{binary(), xmlel()}], boolean()) -> ok | {error, _}.
|
||||||
|
set_data(JID, Data, Publish) ->
|
||||||
|
{LUser, LServer, _} = jid:tolower(JID),
|
||||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||||
case Mod:set_data(LUser, LServer, Data) of
|
case Mod:set_data(LUser, LServer, Data) of
|
||||||
ok ->
|
ok ->
|
||||||
delete_cache(Mod, LUser, LServer, Data);
|
delete_cache(Mod, LUser, LServer, Data),
|
||||||
|
case Publish of
|
||||||
|
true -> publish_data(JID, Data);
|
||||||
|
false -> ok
|
||||||
|
end;
|
||||||
{error, _} = Err ->
|
{error, _} = Err ->
|
||||||
Err
|
Err
|
||||||
end.
|
end.
|
||||||
|
@ -181,6 +225,43 @@ remove_user(User, Server) ->
|
||||||
Mod:del_data(LUser, LServer),
|
Mod:del_data(LUser, LServer),
|
||||||
delete_cache(Mod, LUser, LServer, Data).
|
delete_cache(Mod, LUser, LServer, Data).
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% Pubsub
|
||||||
|
%%%===================================================================
|
||||||
|
-spec publish_data(jid(), [{binary(), xmlel()}]) -> ok | {error, stanza_error()}.
|
||||||
|
publish_data(JID, Data) ->
|
||||||
|
{_, LServer, _} = LBJID = jid:remove_resource(jid:tolower(JID)),
|
||||||
|
case gen_mod:is_loaded(LServer, mod_pubsub) of
|
||||||
|
true ->
|
||||||
|
case lists:keyfind(?NS_STORAGE_BOOKMARKS, 1, Data) of
|
||||||
|
false -> ok;
|
||||||
|
{_, El} ->
|
||||||
|
PubOpts = [{persist_items, true},
|
||||||
|
{access_model, whitelist}],
|
||||||
|
case mod_pubsub:publish_item(
|
||||||
|
LBJID, LServer, ?NS_STORAGE_BOOKMARKS, JID,
|
||||||
|
<<>>, [El], PubOpts, all) of
|
||||||
|
{result, _} -> ok;
|
||||||
|
{error, _} = Err -> Err
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
false ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
-spec pubsub_publish_item(binary(), binary(), jid(), jid(),
|
||||||
|
binary(), [xmlel()]) -> any().
|
||||||
|
pubsub_publish_item(LServer, ?NS_STORAGE_BOOKMARKS,
|
||||||
|
#jid{luser = LUser, lserver = LServer} = From,
|
||||||
|
#jid{luser = LUser, lserver = LServer},
|
||||||
|
_ItemId, [Payload|_]) ->
|
||||||
|
set_data(From, [{?NS_STORAGE_BOOKMARKS, Payload}], false);
|
||||||
|
pubsub_publish_item(_, _, _, _, _, _) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% Cache
|
||||||
|
%%%===================================================================
|
||||||
-spec delete_cache(module(), binary(), binary(), [{binary(), xmlel()}]) -> ok.
|
-spec delete_cache(module(), binary(), binary(), [{binary(), xmlel()}]) -> ok.
|
||||||
delete_cache(Mod, LUser, LServer, Data) ->
|
delete_cache(Mod, LUser, LServer, Data) ->
|
||||||
case use_cache(Mod, LServer) of
|
case use_cache(Mod, LServer) of
|
||||||
|
@ -230,6 +311,9 @@ cache_nodes(Mod, Host) ->
|
||||||
false -> ejabberd_cluster:get_nodes()
|
false -> ejabberd_cluster:get_nodes()
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% Import/Export
|
||||||
|
%%%===================================================================
|
||||||
import_info() ->
|
import_info() ->
|
||||||
[{<<"private_storage">>, 4}].
|
[{<<"private_storage">>, 4}].
|
||||||
|
|
||||||
|
@ -244,21 +328,3 @@ export(LServer) ->
|
||||||
import(LServer, {sql, _}, DBType, Tab, L) ->
|
import(LServer, {sql, _}, DBType, Tab, L) ->
|
||||||
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
Mod = gen_mod:db_mod(DBType, ?MODULE),
|
||||||
Mod:import(LServer, Tab, L).
|
Mod:import(LServer, Tab, L).
|
||||||
|
|
||||||
depends(_Host, _Opts) ->
|
|
||||||
[].
|
|
||||||
|
|
||||||
mod_opt_type(db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
|
|
||||||
mod_opt_type(O) when O == cache_life_time; O == cache_size ->
|
|
||||||
fun (I) when is_integer(I), I > 0 -> I;
|
|
||||||
(infinity) -> infinity
|
|
||||||
end;
|
|
||||||
mod_opt_type(O) when O == use_cache; O == cache_missed ->
|
|
||||||
fun (B) when is_boolean(B) -> B end.
|
|
||||||
|
|
||||||
mod_options(Host) ->
|
|
||||||
[{db_type, ejabberd_config:default_db(Host, ?MODULE)},
|
|
||||||
{use_cache, ejabberd_config:use_cache(Host)},
|
|
||||||
{cache_size, ejabberd_config:cache_size(Host)},
|
|
||||||
{cache_missed, ejabberd_config:cache_missed(Host)},
|
|
||||||
{cache_life_time, ejabberd_config:cache_life_time(Host)}].
|
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
|
|
||||||
%% exports for console debug manual use
|
%% exports for console debug manual use
|
||||||
-export([create_node/5, create_node/7, delete_node/3,
|
-export([create_node/5, create_node/7, delete_node/3,
|
||||||
subscribe_node/5, unsubscribe_node/5, publish_item/6,
|
subscribe_node/5, unsubscribe_node/5, publish_item/6, publish_item/8,
|
||||||
delete_item/4, delete_item/5, send_items/7, get_items/2, get_item/3,
|
delete_item/4, delete_item/5, send_items/7, get_items/2, get_item/3,
|
||||||
get_cached_item/2, get_configure/5, set_configure/5,
|
get_cached_item/2, get_configure/5, set_configure/5,
|
||||||
tree_action/3, node_action/4, node_call/4]).
|
tree_action/3, node_action/4, node_call/4]).
|
||||||
|
|
|
@ -169,8 +169,6 @@ convert_data(Host, "roster", User, [Data]) ->
|
||||||
end, Data),
|
end, Data),
|
||||||
lists:foreach(fun mod_roster:set_roster/1, Rosters);
|
lists:foreach(fun mod_roster:set_roster/1, Rosters);
|
||||||
convert_data(Host, "private", User, [Data]) ->
|
convert_data(Host, "private", User, [Data]) ->
|
||||||
LUser = jid:nodeprep(User),
|
|
||||||
LServer = jid:nameprep(Host),
|
|
||||||
PrivData = lists:flatmap(
|
PrivData = lists:flatmap(
|
||||||
fun({_TagXMLNS, Raw}) ->
|
fun({_TagXMLNS, Raw}) ->
|
||||||
case deserialize(Raw) of
|
case deserialize(Raw) of
|
||||||
|
@ -181,7 +179,7 @@ convert_data(Host, "private", User, [Data]) ->
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
end, Data),
|
end, Data),
|
||||||
mod_private:set_data(LUser, LServer, PrivData);
|
mod_private:set_data(jid:make(User, Host), PrivData);
|
||||||
convert_data(Host, "vcard", User, [Data]) ->
|
convert_data(Host, "vcard", User, [Data]) ->
|
||||||
LServer = jid:nameprep(Host),
|
LServer = jid:nameprep(Host),
|
||||||
case deserialize(Data) of
|
case deserialize(Data) of
|
||||||
|
|
Loading…
Reference in New Issue