aboutsummaryrefslogtreecommitdiff
path: root/src/mod_vcard_mnesia.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_vcard_mnesia.erl')
-rw-r--r--src/mod_vcard_mnesia.erl237
1 files changed, 150 insertions, 87 deletions
diff --git a/src/mod_vcard_mnesia.erl b/src/mod_vcard_mnesia.erl
index 781a135c8..d4394b677 100644
--- a/src/mod_vcard_mnesia.erl
+++ b/src/mod_vcard_mnesia.erl
@@ -1,56 +1,70 @@
%%%-------------------------------------------------------------------
-%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net>
-%%% @copyright (C) 2016, Evgeny Khramtsov
-%%% @doc
-%%%
-%%% @end
+%%% File : mod_vcard_mnesia.erl
+%%% Author : Evgeny Khramtsov <ekhramtsov@process-one.net>
%%% Created : 13 Apr 2016 by Evgeny Khramtsov <ekhramtsov@process-one.net>
-%%%-------------------------------------------------------------------
+%%%
+%%%
+%%% ejabberd, Copyright (C) 2002-2019 ProcessOne
+%%%
+%%% This program is free software; you can redistribute it and/or
+%%% modify it under the terms of the GNU General Public License as
+%%% published by the Free Software Foundation; either version 2 of the
+%%% License, or (at your option) any later version.
+%%%
+%%% This program is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%%% General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License along
+%%% with this program; if not, write to the Free Software Foundation, Inc.,
+%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+%%%
+%%%----------------------------------------------------------------------
+
-module(mod_vcard_mnesia).
-behaviour(mod_vcard).
%% API
--export([init/2, import/2, get_vcard/2, set_vcard/4, search/4, remove_user/2]).
+-export([init/2, stop/1, import/3, get_vcard/2, set_vcard/4, search/4,
+ search_fields/1, search_reported/1, remove_user/2]).
+-export([is_search_supported/1]).
+-export([need_transform/1, transform/1]).
+-export([mod_opt_type/1, mod_options/1]).
--include("ejabberd.hrl").
--include("jlib.hrl").
+-include("xmpp.hrl").
-include("mod_vcard.hrl").
-include("logger.hrl").
+-include("translate.hrl").
%%%===================================================================
%%% API
%%%===================================================================
init(_Host, _Opts) ->
- mnesia:create_table(vcard,
+ ejabberd_mnesia:create(?MODULE, vcard,
[{disc_only_copies, [node()]},
{attributes, record_info(fields, vcard)}]),
- mnesia:create_table(vcard_search,
+ ejabberd_mnesia:create(?MODULE, vcard_search,
[{disc_copies, [node()]},
{attributes,
- record_info(fields, vcard_search)}]),
- update_tables(),
- mnesia:add_table_index(vcard_search, luser),
- mnesia:add_table_index(vcard_search, lfn),
- mnesia:add_table_index(vcard_search, lfamily),
- mnesia:add_table_index(vcard_search, lgiven),
- mnesia:add_table_index(vcard_search, lmiddle),
- mnesia:add_table_index(vcard_search, lnickname),
- mnesia:add_table_index(vcard_search, lbday),
- mnesia:add_table_index(vcard_search, lctry),
- mnesia:add_table_index(vcard_search, llocality),
- mnesia:add_table_index(vcard_search, lemail),
- mnesia:add_table_index(vcard_search, lorgname),
- mnesia:add_table_index(vcard_search, lorgunit).
+ record_info(fields, vcard_search)},
+ {index, [ luser, lfn, lfamily,
+ lgiven, lmiddle, lnickname,
+ lbday, lctry, llocality,
+ lemail, lorgname, lorgunit
+ ]}]).
+
+stop(_Host) ->
+ ok.
+
+is_search_supported(_ServerHost) ->
+ true.
get_vcard(LUser, LServer) ->
US = {LUser, LServer},
- F = fun () -> mnesia:read({vcard, US}) end,
- case mnesia:transaction(F) of
- {atomic, Rs} ->
- lists:map(fun (R) -> R#vcard.vcard end, Rs);
- {aborted, _Reason} -> error
- end.
+ Rs = mnesia:dirty_read(vcard, US),
+ {ok, lists:map(fun (R) -> R#vcard.vcard end, Rs)}.
set_vcard(LUser, LServer, VCARD, VCardSearch) ->
US = {LUser, LServer},
@@ -71,15 +85,44 @@ search(LServer, Data, AllowReturnAll, MaxMatch) ->
{'EXIT', Reason} ->
?ERROR_MSG("~p", [Reason]), [];
Rs ->
+ Fields = lists:map(fun record_to_item/1, Rs),
case MaxMatch of
infinity ->
- Rs;
+ Fields;
Val ->
- lists:sublist(Rs, Val)
+ lists:sublist(Fields, Val)
end
end
end.
+search_fields(_LServer) ->
+ [{?T("User"), <<"user">>},
+ {?T("Full Name"), <<"fn">>},
+ {?T("Name"), <<"first">>},
+ {?T("Middle Name"), <<"middle">>},
+ {?T("Family Name"), <<"last">>},
+ {?T("Nickname"), <<"nick">>},
+ {?T("Birthday"), <<"bday">>},
+ {?T("Country"), <<"ctry">>},
+ {?T("City"), <<"locality">>},
+ {?T("Email"), <<"email">>},
+ {?T("Organization Name"), <<"orgname">>},
+ {?T("Organization Unit"), <<"orgunit">>}].
+
+search_reported(_LServer) ->
+ [{?T("Jabber ID"), <<"jid">>},
+ {?T("Full Name"), <<"fn">>},
+ {?T("Name"), <<"first">>},
+ {?T("Middle Name"), <<"middle">>},
+ {?T("Family Name"), <<"last">>},
+ {?T("Nickname"), <<"nick">>},
+ {?T("Birthday"), <<"bday">>},
+ {?T("Country"), <<"ctry">>},
+ {?T("City"), <<"locality">>},
+ {?T("Email"), <<"email">>},
+ {?T("Organization Name"), <<"orgname">>},
+ {?T("Organization Unit"), <<"orgunit">>}].
+
remove_user(LUser, LServer) ->
US = {LUser, LServer},
F = fun () ->
@@ -88,58 +131,60 @@ remove_user(LUser, LServer) ->
end,
mnesia:transaction(F).
-import(_LServer, #vcard{} = VCard) ->
+import(LServer, <<"vcard">>, [LUser, XML, _TimeStamp]) ->
+ #xmlel{} = El = fxml_stream:parse_element(XML),
+ VCard = #vcard{us = {LUser, LServer}, vcard = El},
mnesia:dirty_write(VCard);
-import(_LServer, #vcard_search{} = S) ->
- mnesia:dirty_write(S).
+import(LServer, <<"vcard_search">>,
+ [User, LUser, FN, LFN,
+ Family, LFamily, Given, LGiven,
+ Middle, LMiddle, Nickname, LNickname,
+ BDay, LBDay, CTRY, LCTRY, Locality, LLocality,
+ EMail, LEMail, OrgName, LOrgName, OrgUnit, LOrgUnit]) ->
+ mnesia:dirty_write(
+ #vcard_search{us = {LUser, LServer},
+ user = {User, LServer}, luser = LUser,
+ fn = FN, lfn = LFN, family = Family,
+ lfamily = LFamily, given = Given,
+ lgiven = LGiven, middle = Middle,
+ lmiddle = LMiddle, nickname = Nickname,
+ lnickname = LNickname, bday = BDay,
+ lbday = LBDay, ctry = CTRY, lctry = LCTRY,
+ locality = Locality, llocality = LLocality,
+ email = EMail, lemail = LEMail,
+ orgname = OrgName, lorgname = LOrgName,
+ orgunit = OrgUnit, lorgunit = LOrgUnit}).
+
+need_transform({vcard, {U, S}, _}) when is_list(U) orelse is_list(S) ->
+ ?INFO_MSG("Mnesia table 'vcard' will be converted to binary", []),
+ true;
+need_transform(R) when element(1, R) == vcard_search ->
+ case element(2, R) of
+ {U, S} when is_list(U) orelse is_list(S) ->
+ ?INFO_MSG("Mnesia table 'vcard_search' will be converted to binary", []),
+ true;
+ _ ->
+ false
+ end;
+need_transform(_) ->
+ false.
+
+transform(#vcard{us = {U, S}, vcard = El} = R) ->
+ R#vcard{us = {iolist_to_binary(U), iolist_to_binary(S)},
+ vcard = fxml:to_xmlel(El)};
+transform(#vcard_search{} = VS) ->
+ [vcard_search | L] = tuple_to_list(VS),
+ NewL = lists:map(
+ fun({U, S}) ->
+ {iolist_to_binary(U), iolist_to_binary(S)};
+ (Str) ->
+ iolist_to_binary(Str)
+ end, L),
+ list_to_tuple([vcard_search | NewL]).
%%%===================================================================
%%% Internal functions
%%%===================================================================
-update_tables() ->
- update_vcard_table(),
- update_vcard_search_table().
-
-update_vcard_table() ->
- Fields = record_info(fields, vcard),
- case mnesia:table_info(vcard, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- vcard, Fields, set,
- fun(#vcard{us = {U, _}}) -> U end,
- fun(#vcard{us = {U, S}, vcard = El} = R) ->
- R#vcard{us = {iolist_to_binary(U),
- iolist_to_binary(S)},
- vcard = fxml:to_xmlel(El)}
- end);
- _ ->
- ?INFO_MSG("Recreating vcard table", []),
- mnesia:transform_table(vcard, ignore, Fields)
- end.
-
-update_vcard_search_table() ->
- Fields = record_info(fields, vcard_search),
- case mnesia:table_info(vcard_search, attributes) of
- Fields ->
- ejabberd_config:convert_table_to_binary(
- vcard_search, Fields, set,
- fun(#vcard_search{us = {U, _}}) -> U end,
- fun(#vcard_search{} = VS) ->
- [vcard_search | L] = tuple_to_list(VS),
- NewL = lists:map(
- fun({U, S}) ->
- {iolist_to_binary(U),
- iolist_to_binary(S)};
- (Str) ->
- iolist_to_binary(Str)
- end, L),
- list_to_tuple([vcard_search | NewL])
- end);
- _ ->
- ?INFO_MSG("Recreating vcard_search table", []),
- mnesia:transform_table(vcard_search, ignore, Fields)
- end.
-
make_matchspec(LServer, Data) ->
GlobMatch = #vcard_search{_ = '_'},
Match = filter_fields(Data, GlobMatch, LServer),
@@ -152,11 +197,7 @@ filter_fields([{SVar, [Val]} | Ds], Match, LServer)
LVal = mod_vcard:string2lower(Val),
NewMatch = case SVar of
<<"user">> ->
- case gen_mod:get_module_opt(LServer, ?MODULE,
- search_all_hosts,
- fun(B) when is_boolean(B) ->
- B
- end, true) of
+ case mod_vcard_mnesia_opt:search_all_hosts(LServer) of
true -> Match#vcard_search{luser = make_val(LVal)};
false ->
Host = find_my_host(LServer),
@@ -197,9 +238,9 @@ make_val(Val) ->
find_my_host(LServer) ->
Parts = str:tokens(LServer, <<".">>),
- find_my_host(Parts, ?MYHOSTS).
+ find_my_host(Parts, ejabberd_option:hosts()).
-find_my_host([], _Hosts) -> ?MYNAME;
+find_my_host([], _Hosts) -> ejabberd_config:get_myname();
find_my_host([_ | Tail] = Parts, Hosts) ->
Domain = parts_to_string(Parts),
case lists:member(Domain, Hosts) of
@@ -211,3 +252,25 @@ parts_to_string(Parts) ->
str:strip(list_to_binary(
lists:map(fun (S) -> <<S/binary, $.>> end, Parts)),
right, $.).
+
+-spec record_to_item(#vcard_search{}) -> [{binary(), binary()}].
+record_to_item(R) ->
+ {User, Server} = R#vcard_search.user,
+ [{<<"jid">>, <<User/binary, "@", Server/binary>>},
+ {<<"fn">>, (R#vcard_search.fn)},
+ {<<"last">>, (R#vcard_search.family)},
+ {<<"first">>, (R#vcard_search.given)},
+ {<<"middle">>, (R#vcard_search.middle)},
+ {<<"nick">>, (R#vcard_search.nickname)},
+ {<<"bday">>, (R#vcard_search.bday)},
+ {<<"ctry">>, (R#vcard_search.ctry)},
+ {<<"locality">>, (R#vcard_search.locality)},
+ {<<"email">>, (R#vcard_search.email)},
+ {<<"orgname">>, (R#vcard_search.orgname)},
+ {<<"orgunit">>, (R#vcard_search.orgunit)}].
+
+mod_opt_type(search_all_hosts) ->
+ econf:bool().
+
+mod_options(_) ->
+ [{search_all_hosts, true}].