mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-20 16:15:59 +01:00
Add support for xep-0402 - PEP Native Bookmarks
This commit is contained in:
parent
c3e0b746d7
commit
765770aaa5
2
mix.exs
2
mix.exs
@ -114,7 +114,7 @@ defmodule Ejabberd.MixProject do
|
||||
{:p1_utils, "~> 1.0"},
|
||||
{:pkix, "~> 1.0"},
|
||||
{:stringprep, ">= 1.0.26"},
|
||||
{:xmpp, git: "https://github.com/processone/xmpp.git", ref: "ef62a043e93c0f472b987847a2a6718714772dcc", override: true},
|
||||
{:xmpp, git: "https://github.com/processone/xmpp.git", ref: "68cb07d5d0f36d5c51bfea496c638f3ee9b36027", override: true},
|
||||
{:yconf, "~> 1.0"}]
|
||||
++ cond_deps()
|
||||
end
|
||||
|
@ -77,7 +77,7 @@
|
||||
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.29"}}},
|
||||
{if_var_true, stun,
|
||||
{stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.2.7"}}}},
|
||||
{xmpp, ".*", {git, "https://github.com/processone/xmpp", "ef62a043e93c0f472b987847a2a6718714772dcc"}},
|
||||
{xmpp, ".*", {git, "https://github.com/processone/xmpp", "68cb07d5d0f36d5c51bfea496c638f3ee9b36027"}},
|
||||
{yconf, ".*", {git, "https://github.com/processone/yconf", {tag, "1.0.15"}}}
|
||||
]}.
|
||||
|
||||
|
@ -29,13 +29,15 @@
|
||||
|
||||
-protocol({xep, 49, '1.2'}).
|
||||
-protocol({xep, 411, '0.2.0', '18.12', "", ""}).
|
||||
-protocol({xep, 402, '1.1.3', '23.09', "", ""}).
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-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, mod_doc/0,
|
||||
import/5, import_start/2, mod_opt_type/1, set_data/2,
|
||||
mod_options/1, depends/2, get_sm_features/5, pubsub_publish_item/6]).
|
||||
mod_options/1, depends/2, get_sm_features/5, pubsub_publish_item/6,
|
||||
pubsub_delete_item/5]).
|
||||
|
||||
-export([get_commands_spec/0, bookmarks_to_pep/2]).
|
||||
|
||||
@ -44,6 +46,7 @@
|
||||
-include("mod_private.hrl").
|
||||
-include("ejabberd_commands.hrl").
|
||||
-include("translate.hrl").
|
||||
-include("pubsub.hrl").
|
||||
|
||||
-define(PRIVATE_CACHE, private_cache).
|
||||
|
||||
@ -66,6 +69,7 @@ start(Host, Opts) ->
|
||||
{ok, [{hook, remove_user, remove_user, 50},
|
||||
{hook, disco_sm_features, get_sm_features, 50},
|
||||
{hook, pubsub_publish_item, pubsub_publish_item, 50},
|
||||
{hook, pubsub_delete_item, pubsub_delete_item, 50},
|
||||
{iq_handler, ejabberd_sm, ?NS_PRIVATE, process_sm_iq}]}.
|
||||
|
||||
stop(Host) ->
|
||||
@ -150,7 +154,7 @@ get_sm_features({error, _Error} = Acc, _From, _To, _Node, _Lang) ->
|
||||
get_sm_features(Acc, _From, To, <<"">>, _Lang) ->
|
||||
case gen_mod:is_loaded(To#jid.lserver, mod_pubsub) of
|
||||
true ->
|
||||
{result, [?NS_BOOKMARKS_CONVERSION_0 |
|
||||
{result, [?NS_BOOKMARKS_CONVERSION_0, ?NS_PEP_BOOKMARKS_COMPAT, ?NS_PEP_BOOKMARKS_COMPAT_PEP |
|
||||
case Acc of
|
||||
{result, Features} -> Features;
|
||||
empty -> []
|
||||
@ -207,17 +211,21 @@ filter_xmlels(Els) ->
|
||||
|
||||
-spec set_data(jid(), [{binary(), xmlel()}]) -> ok | {error, _}.
|
||||
set_data(JID, Data) ->
|
||||
set_data(JID, Data, true).
|
||||
set_data(JID, Data, true, true).
|
||||
|
||||
-spec set_data(jid(), [{binary(), xmlel()}], boolean()) -> ok | {error, _}.
|
||||
set_data(JID, Data, Publish) ->
|
||||
-spec set_data(jid(), [{binary(), xmlel()}], boolean(), boolean()) -> ok | {error, _}.
|
||||
set_data(JID, Data, PublishPepStorageBookmarks, PublishPepXmppBookmarks) ->
|
||||
{LUser, LServer, _} = jid:tolower(JID),
|
||||
Mod = gen_mod:db_mod(LServer, ?MODULE),
|
||||
case Mod:set_data(LUser, LServer, Data) of
|
||||
ok ->
|
||||
delete_cache(Mod, LUser, LServer, Data),
|
||||
case Publish of
|
||||
true -> publish_data(JID, Data);
|
||||
case PublishPepStorageBookmarks of
|
||||
true -> publish_pep_storage_bookmarks(JID, Data);
|
||||
false -> ok
|
||||
end,
|
||||
case PublishPepXmppBookmarks of
|
||||
true -> publish_pep_xmpp_bookmarks(JID, Data);
|
||||
false -> ok
|
||||
end;
|
||||
{error, _} = Err ->
|
||||
@ -278,8 +286,8 @@ remove_user(User, Server) ->
|
||||
%%%===================================================================
|
||||
%%% Pubsub
|
||||
%%%===================================================================
|
||||
-spec publish_data(jid(), [{binary(), xmlel()}]) -> ok | {error, stanza_error()}.
|
||||
publish_data(JID, Data) ->
|
||||
-spec publish_pep_storage_bookmarks(jid(), [{binary(), xmlel()}]) -> ok | {error, stanza_error()}.
|
||||
publish_pep_storage_bookmarks(JID, Data) ->
|
||||
{_, LServer, _} = LBJID = jid:remove_resource(jid:tolower(JID)),
|
||||
case gen_mod:is_loaded(LServer, mod_pubsub) of
|
||||
true ->
|
||||
@ -299,16 +307,154 @@ publish_data(JID, Data) ->
|
||||
ok
|
||||
end.
|
||||
|
||||
-spec publish_pep_xmpp_bookmarks(jid(), [{binary(), xmlel()}]) -> ok | {error, stanza_error()}.
|
||||
publish_pep_xmpp_bookmarks(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
|
||||
{_, Bookmarks0} ->
|
||||
Bookmarks = case xmpp:decode(Bookmarks0) of
|
||||
#bookmark_storage{conference = C} -> C;
|
||||
_ -> []
|
||||
end,
|
||||
PubOpts = [{persist_items, true},
|
||||
{access_model, whitelist},
|
||||
{max_items, max},
|
||||
{notify_retract,true},
|
||||
{notify_delete,true},
|
||||
{send_last_published_item, never}],
|
||||
case mod_pubsub:get_items(LBJID, ?NS_PEP_BOOKMARKS) of
|
||||
PepBookmarks when is_list(PepBookmarks) ->
|
||||
put(mod_private_pep_update, true),
|
||||
PepBookmarksMap = lists:foldl(fun pubsub_item_to_map/2, #{}, PepBookmarks),
|
||||
ToDelete =
|
||||
lists:foldl(
|
||||
fun(#bookmark_conference{jid = BookmarkJID} = Bookmark, Map2) ->
|
||||
PB = storage_bookmark_to_xmpp_bookmark(Bookmark),
|
||||
case maps:take(jid:tolower(BookmarkJID), Map2) of
|
||||
{StoredBookmark, Map3} when StoredBookmark == PB ->
|
||||
Map3;
|
||||
{_, Map4} ->
|
||||
mod_pubsub:publish_item(
|
||||
LBJID, LServer, ?NS_PEP_BOOKMARKS, JID,
|
||||
jid:encode(BookmarkJID), [xmpp:encode(PB)], PubOpts, all),
|
||||
Map4;
|
||||
_ ->
|
||||
mod_pubsub:publish_item(
|
||||
LBJID, LServer, ?NS_PEP_BOOKMARKS, JID,
|
||||
jid:encode(BookmarkJID), [xmpp:encode(PB)], PubOpts, all),
|
||||
Map2
|
||||
end
|
||||
end, PepBookmarksMap, Bookmarks),
|
||||
maps:fold(
|
||||
fun(DeleteJid, _, _) ->
|
||||
mod_pubsub:delete_item(LBJID, ?NS_PEP_BOOKMARKS, JID, jid:encode(DeleteJid))
|
||||
end, ok, ToDelete),
|
||||
erase(mod_private_pep_update),
|
||||
ok;
|
||||
{error, #stanza_error{reason = 'item-not-found'}} ->
|
||||
put(mod_private_pep_update, true),
|
||||
lists:foreach(
|
||||
fun(#bookmark_conference{jid = BookmarkJID} = Bookmark) ->
|
||||
PB = storage_bookmark_to_xmpp_bookmark(Bookmark),
|
||||
mod_pubsub:publish_item(
|
||||
LBJID, LServer, ?NS_PEP_BOOKMARKS, JID,
|
||||
jid:encode(BookmarkJID), [xmpp:encode(PB)], PubOpts, all)
|
||||
end, Bookmarks),
|
||||
erase(mod_private_pep_update),
|
||||
ok;
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
ok
|
||||
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);
|
||||
set_data(From, [{?NS_STORAGE_BOOKMARKS, Payload}], false, true);
|
||||
pubsub_publish_item(LServer, ?NS_PEP_BOOKMARKS,
|
||||
#jid{luser = LUser, lserver = LServer} = From,
|
||||
#jid{luser = LUser, lserver = LServer},
|
||||
_ItemId, _Payload) ->
|
||||
NotRecursion = get(mod_private_pep_update) == undefined,
|
||||
case mod_pubsub:get_items({LUser, LServer, <<>>}, ?NS_PEP_BOOKMARKS) of
|
||||
Bookmarks when is_list(Bookmarks), NotRecursion ->
|
||||
Bookmarks2 = lists:filtermap(fun pubsub_item_to_storage_bookmark/1, Bookmarks),
|
||||
Payload = xmpp:encode(#bookmark_storage{conference = Bookmarks2}),
|
||||
set_data(From, [{?NS_STORAGE_BOOKMARKS, Payload}], true, false);
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
pubsub_publish_item(_, _, _, _, _, _) ->
|
||||
ok.
|
||||
|
||||
-spec pubsub_delete_item(binary(), binary(), jid(), jid(), binary()) -> any().
|
||||
pubsub_delete_item(LServer, ?NS_PEP_BOOKMARKS,
|
||||
#jid{luser = LUser, lserver = LServer} = From,
|
||||
#jid{luser = LUser, lserver = LServer},
|
||||
_ItemId) ->
|
||||
NotRecursion = get(mod_private_pep_update) == undefined,
|
||||
case mod_pubsub:get_items({LUser, LServer, <<>>}, ?NS_PEP_BOOKMARKS) of
|
||||
Bookmarks when is_list(Bookmarks), NotRecursion ->
|
||||
Bookmarks2 = lists:filtermap(fun pubsub_item_to_storage_bookmark/1, Bookmarks),
|
||||
Payload = xmpp:encode(#bookmark_storage{conference = Bookmarks2}),
|
||||
set_data(From, [{?NS_STORAGE_BOOKMARKS, Payload}], true, false);
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
pubsub_delete_item(_, _, _, _, _) ->
|
||||
ok.
|
||||
|
||||
-spec pubsub_item_to_storage_bookmark(#pubsub_item{}) -> {true, bookmark_conference()} | false.
|
||||
pubsub_item_to_storage_bookmark(#pubsub_item{itemid = {Id, _}, payload = [#xmlel{} = B | _]}) ->
|
||||
case xmpp:decode(B) of
|
||||
#pep_bookmarks_conference{name = Name, autojoin = AutoJoin, nick = Nick,
|
||||
password = Password} ->
|
||||
try jid:decode(Id) of
|
||||
#jid{} = Jid ->
|
||||
{true, #bookmark_conference{jid = Jid, name = Name, autojoin = AutoJoin, nick = Nick,
|
||||
password = Password}}
|
||||
catch _:_ ->
|
||||
false
|
||||
end;
|
||||
_ ->
|
||||
false
|
||||
end;
|
||||
pubsub_item_to_storage_bookmark(_) ->
|
||||
false.
|
||||
|
||||
-spec storage_bookmark_to_xmpp_bookmark(bookmark_conference()) -> pep_bookmarks_conference().
|
||||
storage_bookmark_to_xmpp_bookmark(#bookmark_conference{name = Name, autojoin = AutoJoin, nick = Nick,
|
||||
password = Password}) ->
|
||||
#pep_bookmarks_conference{name = Name, autojoin = AutoJoin, nick = Nick,
|
||||
password = Password}.
|
||||
|
||||
-spec pubsub_item_to_map(#pubsub_item{}, map()) -> map().
|
||||
pubsub_item_to_map(#pubsub_item{itemid = {Id, _}, payload = [#xmlel{} = B | _]}, Map) ->
|
||||
?INFO_MSG("DECODING ~p", [B]),
|
||||
case xmpp:decode(B) of
|
||||
#pep_bookmarks_conference{} = B2 ->
|
||||
try jid:decode(Id) of
|
||||
#jid{} = Jid ->
|
||||
maps:put(jid:tolower(Jid), B2#pep_bookmarks_conference{extensions = undefined}, Map)
|
||||
catch _:_ ->
|
||||
Map
|
||||
end;
|
||||
_ ->
|
||||
Map
|
||||
end;
|
||||
pubsub_item_to_map(_, Map) ->
|
||||
Map.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Commands
|
||||
%%%===================================================================
|
||||
@ -344,11 +490,17 @@ bookmarks_to_pep(User, Server) ->
|
||||
case Res of
|
||||
{ok, El} ->
|
||||
Data = [{?NS_STORAGE_BOOKMARKS, El}],
|
||||
case publish_data(jid:make(User, Server), Data) of
|
||||
case publish_pep_storage_bookmarks(jid:make(User, Server), Data) of
|
||||
ok ->
|
||||
{ok, <<"Bookmarks exported to PEP node">>};
|
||||
case publish_pep_xmpp_bookmarks(jid:make(User, Server), Data) of
|
||||
ok ->
|
||||
{ok, <<"Bookmarks exported to PEP node">>};
|
||||
{error, Err} ->
|
||||
{error, xmpp:format_stanza_error(Err)}
|
||||
end;
|
||||
{error, Err} ->
|
||||
{error, xmpp:format_stanza_error(Err)}
|
||||
|
||||
end;
|
||||
_ ->
|
||||
{error, <<"Cannot retrieve bookmarks from private XML storage">>}
|
||||
|
Loading…
Reference in New Issue
Block a user