1 |
|
-module(mod_vcard_mnesia). |
2 |
|
|
3 |
|
-behaviour(mod_vcard_backend). |
4 |
|
|
5 |
|
%% mod_vcards callbacks |
6 |
|
-export([init/2, |
7 |
|
remove_user/3, |
8 |
|
get_vcard/3, |
9 |
|
set_vcard/5, |
10 |
|
search/3, |
11 |
|
search_fields/2, |
12 |
|
search_reported_fields/3]). |
13 |
|
|
14 |
|
-include("mongoose.hrl"). |
15 |
|
-include("jlib.hrl"). |
16 |
|
-include("mod_vcard.hrl"). |
17 |
|
|
18 |
|
init(_HostType, _Options) -> |
19 |
413 |
prepare_db(), |
20 |
413 |
ok. |
21 |
|
|
22 |
|
remove_user(_HostType, LUser, LServer) -> |
23 |
3031 |
US = {LUser, LServer}, |
24 |
3031 |
F = fun() -> |
25 |
3031 |
mnesia:delete({vcard, US}), |
26 |
3031 |
mnesia:delete({vcard_search, US}) |
27 |
|
end, |
28 |
3031 |
mnesia:transaction(F). |
29 |
|
|
30 |
|
get_vcard(_HostType, LUser, LServer) -> |
31 |
83 |
US = {LUser, LServer}, |
32 |
83 |
F = fun() -> |
33 |
83 |
mnesia:read({vcard, US}) |
34 |
|
end, |
35 |
83 |
case mnesia:transaction(F) of |
36 |
|
{atomic, []} -> |
37 |
54 |
{error, mongoose_xmpp_errors:item_not_found()}; |
38 |
|
{atomic, Rs} -> |
39 |
29 |
Els = lists:map(fun(R) -> |
40 |
29 |
R#vcard.vcard |
41 |
|
end, Rs), |
42 |
29 |
{ok, Els}; |
43 |
|
{aborted, Reason} -> |
44 |
:-( |
?LOG_ERROR(#{what => process_sm_iq_vcard_lookup_failed, |
45 |
:-( |
reason => Reason, user => LUser, server => LServer}), |
46 |
:-( |
{error, mongoose_xmpp_errors:internal_server_error()} |
47 |
|
end. |
48 |
|
|
49 |
|
set_vcard(HostType, User, LServer, VCard, VCardSearch) -> |
50 |
30 |
LUser = jid:nodeprep(User), |
51 |
30 |
VCardSearch2 = stringify_search_fields(VCardSearch), |
52 |
30 |
F = fun() -> |
53 |
30 |
mnesia:write(#vcard{us ={LUser, LServer}, vcard = VCard}), |
54 |
30 |
mnesia:write(VCardSearch2) |
55 |
|
end, |
56 |
30 |
{atomic, _} = mnesia:transaction(F), |
57 |
30 |
mongoose_hooks:vcard_set(HostType, LServer, LUser, VCard), |
58 |
30 |
ok. |
59 |
|
|
60 |
|
-spec search(mongooseim:host_type(), jid:lserver(), term()) -> [[mongoose_data_forms:field()]]. |
61 |
|
search(HostType, LServer, Data) -> |
62 |
19 |
MatchHead = make_matchhead(LServer, Data), |
63 |
19 |
R = do_search(HostType, LServer, MatchHead), |
64 |
19 |
lists:map(fun record_to_item/1, R). |
65 |
|
|
66 |
|
do_search(_, _, #vcard_search{_ = '_'}) -> |
67 |
2 |
[]; |
68 |
|
do_search(HostType, LServer, MatchHeadIn) -> |
69 |
17 |
MatchHead = MatchHeadIn#vcard_search{us = {'_', LServer}}, |
70 |
17 |
case catch mnesia:dirty_select(vcard_search, |
71 |
|
[{MatchHead, [], ['$_']}]) of |
72 |
|
{'EXIT', Reason} -> |
73 |
:-( |
?LOG_ERROR(#{what => vcard_search_failed, server => LServer, host_type => HostType, |
74 |
:-( |
reason => Reason}), |
75 |
:-( |
[]; |
76 |
|
Rs -> |
77 |
17 |
case mod_vcard:get_results_limit(HostType) of |
78 |
|
infinity -> |
79 |
:-( |
Rs; |
80 |
|
Val -> |
81 |
17 |
lists:sublist(Rs, Val) |
82 |
|
end |
83 |
|
end. |
84 |
|
|
85 |
|
search_fields(_HostType, _LServer) -> |
86 |
2 |
mod_vcard:default_search_fields(). |
87 |
|
|
88 |
|
-spec search_reported_fields(mongooseim:host_type(), jid:lserver(), ejabberd:lang()) -> |
89 |
|
[mongoose_data_forms:field()]. |
90 |
|
search_reported_fields(_HostType, _LServer, Lang) -> |
91 |
19 |
mod_vcard:get_default_reported_fields(Lang). |
92 |
|
|
93 |
|
%%-------------------------------------------------------------------- |
94 |
|
%% internal |
95 |
|
%%-------------------------------------------------------------------- |
96 |
|
|
97 |
|
prepare_db() -> |
98 |
413 |
create_tables(), |
99 |
413 |
set_indexes(), |
100 |
413 |
add_table_copies(). |
101 |
|
|
102 |
|
create_tables() -> |
103 |
413 |
mongoose_mnesia:create_table(vcard, |
104 |
|
[{disc_only_copies, [node()]}, |
105 |
|
{attributes, record_info(fields, vcard)}]), |
106 |
413 |
mongoose_mnesia:create_table(vcard_search, |
107 |
|
[{disc_copies, [node()]}, |
108 |
|
{attributes, record_info(fields, vcard_search)}]). |
109 |
|
|
110 |
|
add_table_copies() -> |
111 |
413 |
mnesia:add_table_copy(vcard, node(), disc_only_copies), |
112 |
413 |
mnesia:add_table_copy(vcard_search, node(), disc_copies). |
113 |
|
|
114 |
|
set_indexes() -> |
115 |
413 |
mnesia:add_table_index(vcard_search, luser), |
116 |
413 |
mnesia:add_table_index(vcard_search, lfn), |
117 |
413 |
mnesia:add_table_index(vcard_search, lfamily), |
118 |
413 |
mnesia:add_table_index(vcard_search, lgiven), |
119 |
413 |
mnesia:add_table_index(vcard_search, lmiddle), |
120 |
413 |
mnesia:add_table_index(vcard_search, lnickname), |
121 |
413 |
mnesia:add_table_index(vcard_search, lbday), |
122 |
413 |
mnesia:add_table_index(vcard_search, lctry), |
123 |
413 |
mnesia:add_table_index(vcard_search, llocality), |
124 |
413 |
mnesia:add_table_index(vcard_search, lemail), |
125 |
413 |
mnesia:add_table_index(vcard_search, lorgname), |
126 |
413 |
mnesia:add_table_index(vcard_search, lorgunit). |
127 |
|
|
128 |
|
make_matchhead(LServer, Data) -> |
129 |
19 |
GlobMatch = #vcard_search{_ = '_'}, |
130 |
19 |
Match = filter_fields(Data, GlobMatch, LServer), |
131 |
19 |
Match. |
132 |
|
|
133 |
|
filter_fields([], Match, _LServer) -> |
134 |
19 |
Match; |
135 |
|
filter_fields([{SVar, [Val]} | Ds], Match, LServer) |
136 |
|
when is_binary(Val) and (Val /= <<"">>) -> |
137 |
18 |
LVal = jid:str_tolower(Val), |
138 |
18 |
NewMatch = |
139 |
|
case SVar of |
140 |
:-( |
<<"user">> -> Match#vcard_search{luser = make_val(LVal)}; |
141 |
14 |
<<"fn">> -> Match#vcard_search{lfn = make_val(LVal)}; |
142 |
2 |
<<"last">> -> Match#vcard_search{lfamily = make_val(LVal)}; |
143 |
1 |
<<"first">> -> Match#vcard_search{lgiven = make_val(LVal)}; |
144 |
:-( |
<<"middle">> -> Match#vcard_search{lmiddle = make_val(LVal)}; |
145 |
:-( |
<<"nick">> -> Match#vcard_search{lnickname = make_val(LVal)}; |
146 |
:-( |
<<"bday">> -> Match#vcard_search{lbday = make_val(LVal)}; |
147 |
:-( |
<<"ctry">> -> Match#vcard_search{lctry = make_val(LVal)}; |
148 |
1 |
<<"locality">> -> Match#vcard_search{llocality = make_val(LVal)}; |
149 |
:-( |
<<"email">> -> Match#vcard_search{lemail = make_val(LVal)}; |
150 |
:-( |
<<"orgname">> -> Match#vcard_search{lorgname = make_val(LVal)}; |
151 |
:-( |
<<"orgunit">> -> Match#vcard_search{lorgunit = make_val(LVal)}; |
152 |
:-( |
_ -> Match |
153 |
|
end, |
154 |
18 |
filter_fields(Ds, NewMatch, LServer); |
155 |
|
filter_fields([_ | Ds], Match, LServer) -> |
156 |
:-( |
filter_fields(Ds, Match, LServer). |
157 |
|
|
158 |
|
%% Fulltext search is mnesia is something that is really-really wrong |
159 |
|
stringify_search_fields(#vcard_search{} = S) -> |
160 |
30 |
S#vcard_search{ |
161 |
|
lfn = binary_to_list(S#vcard_search.lfn), |
162 |
|
lfamily = binary_to_list(S#vcard_search.lfamily), |
163 |
|
luser = binary_to_list(S#vcard_search.luser), |
164 |
|
lgiven = binary_to_list(S#vcard_search.lgiven), |
165 |
|
lmiddle = binary_to_list(S#vcard_search.lmiddle), |
166 |
|
lnickname = binary_to_list(S#vcard_search.lnickname), |
167 |
|
lbday = binary_to_list(S#vcard_search.lbday), |
168 |
|
lctry = binary_to_list(S#vcard_search.lctry), |
169 |
|
llocality = binary_to_list(S#vcard_search.llocality), |
170 |
|
lemail = binary_to_list(S#vcard_search.lemail), |
171 |
|
lorgname = binary_to_list(S#vcard_search.lorgname), |
172 |
|
lorgunit = binary_to_list(S#vcard_search.lorgunit) |
173 |
|
}. |
174 |
|
|
175 |
|
%% returns value as list to match substrings using match spec. |
176 |
|
%% See vcard_search definition. |
177 |
|
make_val(ValBin) -> |
178 |
18 |
Val = binary_to_list(ValBin), |
179 |
18 |
case lists:suffix("*", Val) of |
180 |
|
true -> |
181 |
11 |
lists:sublist(Val, length(Val) - 1) ++ '_'; |
182 |
|
_ -> |
183 |
7 |
Val |
184 |
|
end. |
185 |
|
|
186 |
|
record_to_item(R) -> |
187 |
25 |
{User, Server} = R#vcard_search.user, |
188 |
25 |
[ |
189 |
|
?FIELD(<<"jid">>, <<User/binary, $@, Server/binary>>), |
190 |
|
?FIELD(<<"fn">>, (R#vcard_search.fn)), |
191 |
|
?FIELD(<<"last">>, (R#vcard_search.family)), |
192 |
|
?FIELD(<<"first">>, (R#vcard_search.given)), |
193 |
|
?FIELD(<<"middle">>, (R#vcard_search.middle)), |
194 |
|
?FIELD(<<"nick">>, (R#vcard_search.nickname)), |
195 |
|
?FIELD(<<"bday">>, (R#vcard_search.bday)), |
196 |
|
?FIELD(<<"ctry">>, (R#vcard_search.ctry)), |
197 |
|
?FIELD(<<"locality">>, (R#vcard_search.locality)), |
198 |
|
?FIELD(<<"email">>, (R#vcard_search.email)), |
199 |
|
?FIELD(<<"orgname">>, (R#vcard_search.orgname)), |
200 |
|
?FIELD(<<"orgunit">>, (R#vcard_search.orgunit)) |
201 |
|
]. |