1 |
|
%%%---------------------------------------------------------------------- |
2 |
|
%%% File : mod_vcard_ldap.erl |
3 |
|
%%% Author : Alexey Shchepin <alexey@process-one.net> |
4 |
|
%%% Purpose : Support for VCards from LDAP storage. |
5 |
|
%%% Created : 2 Jan 2003 by Alexey Shchepin <alexey@process-one.net> |
6 |
|
%%% |
7 |
|
%%% |
8 |
|
%%% ejabberd, Copyright (C) 2002-2013 ProcessOne |
9 |
|
%%% |
10 |
|
%%% This program is free software; you can redistribute it and/or |
11 |
|
%%% modify it under the terms of the GNU General Public License as |
12 |
|
%%% published by the Free Software Foundation; either version 2 of the |
13 |
|
%%% License, or (at your option) any later version. |
14 |
|
%%% |
15 |
|
%%% This program is distributed in the hope that it will be useful, |
16 |
|
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 |
|
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 |
|
%%% General Public License for more details. |
19 |
|
%%% |
20 |
|
%%% You should have received a copy of the GNU General Public License |
21 |
|
%%% along with this program; if not, write to the Free Software |
22 |
|
%%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
23 |
|
%%% |
24 |
|
%%%---------------------------------------------------------------------- |
25 |
|
|
26 |
|
-module(mod_vcard_ldap). |
27 |
|
-author('alexey@process-one.net'). |
28 |
|
|
29 |
|
-behaviour(mod_vcard_backend). |
30 |
|
|
31 |
|
%% mod_vcard_backend callbacks |
32 |
|
-export([init/2, |
33 |
|
tear_down/1, |
34 |
|
remove_user/3, |
35 |
|
get_vcard/3, |
36 |
|
set_vcard/5, |
37 |
|
search/3, |
38 |
|
search_fields/2, |
39 |
|
search_reported_fields/3]). |
40 |
|
|
41 |
|
-export([default_vcard_map/0, |
42 |
|
default_search_fields/0, |
43 |
|
default_search_reported/0]). |
44 |
|
|
45 |
|
-include_lib("eldap/include/eldap.hrl"). |
46 |
|
-include("mod_vcard.hrl"). |
47 |
|
-include("jlib.hrl"). |
48 |
|
|
49 |
|
-record(state, |
50 |
|
{serverhost = <<>> :: binary(), |
51 |
|
myhost = <<>> :: binary(), |
52 |
|
eldap_id :: eldap_utils:eldap_id(), |
53 |
|
base = <<>> :: binary(), |
54 |
|
password = <<>> :: binary(), |
55 |
|
uids = [] :: [{binary()} | {binary(), binary()}], |
56 |
|
vcard_map = [] :: [{binary(), binary(), [binary()]}], |
57 |
|
vcard_map_attrs = [] :: [binary()], |
58 |
|
user_filter = <<>> :: binary(), |
59 |
|
search_filter :: eldap_utils:filter(), |
60 |
|
search_fields = [] :: [{binary(), binary()}], |
61 |
|
search_reported = [] :: [{binary(), binary()}], |
62 |
|
search_reported_attrs = [] :: [binary()], |
63 |
|
search_operator :: 'or' | 'and', |
64 |
|
binary_search_fields :: [binary()], |
65 |
|
deref = neverDerefAliases :: eldap_utils:deref(), |
66 |
|
matches = 0 :: non_neg_integer() | infinity}). |
67 |
|
|
68 |
|
-define(VCARD_MAP, |
69 |
|
[{<<"NICKNAME">>, <<"%u">>, []}, |
70 |
|
{<<"FN">>, <<"%s">>, [<<"displayName">>]}, |
71 |
|
{<<"FAMILY">>, <<"%s">>, [<<"sn">>]}, |
72 |
|
{<<"GIVEN">>, <<"%s">>, [<<"givenName">>]}, |
73 |
|
{<<"MIDDLE">>, <<"%s">>, [<<"initials">>]}, |
74 |
|
{<<"ORGNAME">>, <<"%s">>, [<<"o">>]}, |
75 |
|
{<<"ORGUNIT">>, <<"%s">>, [<<"ou">>]}, |
76 |
|
{<<"CTRY">>, <<"%s">>, [<<"c">>]}, |
77 |
|
{<<"LOCALITY">>, <<"%s">>, [<<"l">>]}, |
78 |
|
{<<"STREET">>, <<"%s">>, [<<"street">>]}, |
79 |
|
{<<"REGION">>, <<"%s">>, [<<"st">>]}, |
80 |
|
{<<"PCODE">>, <<"%s">>, [<<"postalCode">>]}, |
81 |
|
{<<"TITLE">>, <<"%s">>, [<<"title">>]}, |
82 |
|
{<<"URL">>, <<"%s">>, [<<"labeleduri">>]}, |
83 |
|
{<<"DESC">>, <<"%s">>, [<<"description">>]}, |
84 |
|
{<<"TEL">>, <<"%s">>, [<<"telephoneNumber">>]}, |
85 |
|
{<<"EMAIL">>, <<"%s">>, [<<"mail">>]}, |
86 |
|
{<<"BDAY">>, <<"%s">>, [<<"birthDay">>]}, |
87 |
|
{<<"ROLE">>, <<"%s">>, [<<"employeeType">>]}, |
88 |
|
{<<"PHOTO">>, <<"%s">>, [<<"jpegPhoto">>]}]). |
89 |
|
|
90 |
|
-define(SEARCH_FIELDS, |
91 |
|
[{<<"User">>, <<"%u">>}, |
92 |
|
{<<"Full Name">>, <<"displayName">>}, |
93 |
|
{<<"Given Name">>, <<"givenName">>}, |
94 |
|
{<<"Middle Name">>, <<"initials">>}, |
95 |
|
{<<"Family Name">>, <<"sn">>}, |
96 |
|
{<<"Nickname">>, <<"%u">>}, |
97 |
|
{<<"Birthday">>, <<"birthDay">>}, |
98 |
|
{<<"Country">>, <<"c">>}, {<<"City">>, <<"l">>}, |
99 |
|
{<<"Email">>, <<"mail">>}, |
100 |
|
{<<"Organization Name">>, <<"o">>}, |
101 |
|
{<<"Organization Unit">>, <<"ou">>}]). |
102 |
|
|
103 |
|
-define(SEARCH_REPORTED, |
104 |
|
[{<<"Full Name">>, <<"FN">>}, |
105 |
|
{<<"Given Name">>, <<"FIRST">>}, |
106 |
|
{<<"Middle Name">>, <<"MIDDLE">>}, |
107 |
|
{<<"Family Name">>, <<"LAST">>}, |
108 |
|
{<<"Nickname">>, <<"NICK">>}, |
109 |
|
{<<"Birthday">>, <<"BDAY">>}, |
110 |
|
{<<"Country">>, <<"CTRY">>}, |
111 |
|
{<<"City">>, <<"LOCALITY">>}, |
112 |
|
{<<"Email">>, <<"EMAIL">>}, |
113 |
|
{<<"Organization Name">>, <<"ORGNAME">>}, |
114 |
|
{<<"Organization Unit">>, <<"ORGUNIT">>}]). |
115 |
|
|
116 |
|
|
117 |
|
|
118 |
|
%%-------------------------------------------------------------------- |
119 |
|
%% mod_vcard_backend callbacks |
120 |
|
%%-------------------------------------------------------------------- |
121 |
|
-spec init(mongooseim:host_type(), gen_mod:module_opts()) -> ok. |
122 |
|
init(_HostType, _Opts) -> |
123 |
:-( |
ok. |
124 |
|
|
125 |
|
-spec tear_down(mongooseim:host_type()) -> ok. |
126 |
|
tear_down(HostType) -> |
127 |
:-( |
clear_persistent_term(HostType), |
128 |
:-( |
ok. |
129 |
|
|
130 |
|
-spec remove_user(mongooseim:host_type(), jid:luser(), jid:lserver()) -> ok. |
131 |
|
remove_user(_HostType, _LUser, _LServer) -> |
132 |
|
%% no need to handle this - in ldap |
133 |
|
%% removing user = delete all user info |
134 |
:-( |
ok. |
135 |
|
|
136 |
|
-spec get_vcard(mongooseim:host_type(), jid:luser(), jid:lserver()) -> {ok, [exml:element()]}. |
137 |
|
get_vcard(HostType, LUser, LServer) -> |
138 |
:-( |
State = get_state(HostType, LServer), |
139 |
:-( |
JID = jid:make_bare(LUser, LServer), |
140 |
:-( |
case ejabberd_auth:does_user_exist(JID) of |
141 |
|
true -> |
142 |
:-( |
case find_ldap_user(LUser, State) of |
143 |
|
#eldap_entry{attributes = Attributes} -> |
144 |
:-( |
VCardMap = State#state.vcard_map, |
145 |
:-( |
VCard = ldap_attributes_to_vcard(Attributes, VCardMap, {LUser, LServer}), |
146 |
:-( |
{ok, VCard}; |
147 |
|
_ -> |
148 |
:-( |
{ok, []} |
149 |
|
end; |
150 |
|
_ -> |
151 |
:-( |
{ok, []} |
152 |
|
end. |
153 |
|
|
154 |
|
-spec set_vcard(mongooseim:host_type(), jid:luser(), jid:lserver(), exml:element(), mod_vcard:vcard_search()) -> |
155 |
|
{error, exml:element()}. |
156 |
|
set_vcard(_HostType, _User, _LServer, _VCard, _VCardSearch) -> |
157 |
:-( |
{error, mongoose_xmpp_errors:not_allowed()}. |
158 |
|
|
159 |
|
-spec search(mongooseim:host_type(), jid:lserver(), [{binary(), [binary()]}]) -> |
160 |
|
[[mongoose_data_forms:field()]]. |
161 |
|
search(HostType, LServer, Data) -> |
162 |
:-( |
State = get_state(HostType, LServer), |
163 |
:-( |
search_internal(State, Data). |
164 |
|
|
165 |
|
-spec search_fields(mongooseim:host_type(), jid:lserver()) -> [{binary(), binary()}]. |
166 |
|
search_fields(HostType, LServer) -> |
167 |
:-( |
State = get_state(HostType, LServer), |
168 |
:-( |
State#state.search_fields. |
169 |
|
|
170 |
|
-spec search_reported_fields(mongooseim:host_type(), jid:lserver(), binary()) -> |
171 |
|
[mongoose_data_forms:field()]. |
172 |
|
search_reported_fields(HostType, LServer, Lang) -> |
173 |
:-( |
State = get_state(HostType, LServer), |
174 |
:-( |
SearchReported = State#state.search_reported, |
175 |
:-( |
[?TLFIELD(<<"text-single">>, Name, Value) || |
176 |
:-( |
{Name, Value} <- [{<<"Jabber ID">>, <<"jid">>} | SearchReported]]. |
177 |
|
|
178 |
|
%%-------------------------------------------------------------------- |
179 |
|
%% API |
180 |
|
%%-------------------------------------------------------------------- |
181 |
|
default_vcard_map() -> |
182 |
106 |
?VCARD_MAP. |
183 |
|
|
184 |
|
default_search_fields() -> |
185 |
106 |
?SEARCH_FIELDS. |
186 |
|
|
187 |
|
default_search_reported() -> |
188 |
106 |
?SEARCH_REPORTED. |
189 |
|
|
190 |
|
%%-------------------------------------------------------------------- |
191 |
|
%% Internal |
192 |
|
%%-------------------------------------------------------------------- |
193 |
|
find_ldap_user(User, State) -> |
194 |
:-( |
Base = State#state.base, |
195 |
:-( |
RFC2254Filter = State#state.user_filter, |
196 |
:-( |
EldapID = State#state.eldap_id, |
197 |
:-( |
VCardAttrs = State#state.vcard_map_attrs, |
198 |
:-( |
case eldap_filter:parse(RFC2254Filter, [{<<"%u">>, User}]) of |
199 |
|
{ok, EldapFilter} -> |
200 |
:-( |
Res = eldap_pool_search(EldapID, Base, EldapFilter, State#state.deref, VCardAttrs, false), |
201 |
:-( |
case Res of |
202 |
|
[H | _] -> |
203 |
:-( |
H; |
204 |
|
_ -> |
205 |
:-( |
Res |
206 |
|
end; |
207 |
:-( |
_ -> false |
208 |
|
end. |
209 |
|
|
210 |
|
eldap_pool_search(EldapID, Base, EldapFilter, Deref, Attrs, NoResultRes) -> |
211 |
:-( |
SearchOpts = search_opts(Base, EldapFilter, Deref, Attrs), |
212 |
:-( |
case eldap_pool:search(EldapID, SearchOpts) of |
213 |
:-( |
#eldap_search_result{entries = E} -> E; |
214 |
:-( |
_ -> NoResultRes |
215 |
|
end. |
216 |
|
|
217 |
|
search_opts(Base, EldapFilter, Deref, Attrs) -> |
218 |
:-( |
[{base, Base}, {filter, EldapFilter}, |
219 |
|
{deref, Deref}, {attributes, Attrs}]. |
220 |
|
|
221 |
|
ldap_attributes_to_vcard(Attributes, VCardMap, UD) -> |
222 |
:-( |
Attrs = lists:map(fun ({VCardName, _, _}) -> |
223 |
:-( |
{jid:str_tolower(VCardName), |
224 |
|
map_vcard_attr(VCardName, Attributes, VCardMap, |
225 |
|
UD)} |
226 |
|
end, |
227 |
|
VCardMap), |
228 |
:-( |
Elts = [ldap_attribute_to_vcard(vCard, Attr) |
229 |
:-( |
|| Attr <- Attrs], |
230 |
:-( |
NElts = [ldap_attribute_to_vcard(vCardN, Attr) |
231 |
:-( |
|| Attr <- Attrs], |
232 |
:-( |
OElts = [ldap_attribute_to_vcard(vCardO, Attr) |
233 |
:-( |
|| Attr <- Attrs], |
234 |
:-( |
AElts = [ldap_attribute_to_vcard(vCardA, Attr) |
235 |
:-( |
|| Attr <- Attrs], |
236 |
:-( |
[#xmlel{name = <<"vCard">>, |
237 |
|
attrs = [{<<"xmlns">>, ?NS_VCARD}], |
238 |
|
children = |
239 |
:-( |
lists:append([X || X <- Elts, X /= none], |
240 |
|
[#xmlel{name = <<"N">>, attrs = [], |
241 |
:-( |
children = [X || X <- NElts, X /= none]}, |
242 |
|
#xmlel{name = <<"ORG">>, attrs = [], |
243 |
:-( |
children = [X || X <- OElts, X /= none]}, |
244 |
|
#xmlel{name = <<"ADR">>, attrs = [], |
245 |
|
children = |
246 |
:-( |
[X || X <- AElts, X /= none]}])}]. |
247 |
|
|
248 |
|
ldap_attribute_to_vcard(vCard, {<<"fn">>, Value}) -> |
249 |
:-( |
#xmlel{name = <<"FN">>, attrs = [], |
250 |
|
children = [{xmlcdata, Value}]}; |
251 |
|
ldap_attribute_to_vcard(vCard, |
252 |
|
{<<"nickname">>, Value}) -> |
253 |
:-( |
#xmlel{name = <<"NICKNAME">>, attrs = [], |
254 |
|
children = [{xmlcdata, Value}]}; |
255 |
|
ldap_attribute_to_vcard(vCard, {<<"title">>, Value}) -> |
256 |
:-( |
#xmlel{name = <<"TITLE">>, attrs = [], |
257 |
|
children = [{xmlcdata, Value}]}; |
258 |
|
ldap_attribute_to_vcard(vCard, {<<"bday">>, Value}) -> |
259 |
:-( |
#xmlel{name = <<"BDAY">>, attrs = [], |
260 |
|
children = [{xmlcdata, Value}]}; |
261 |
|
ldap_attribute_to_vcard(vCard, {<<"url">>, Value}) -> |
262 |
:-( |
#xmlel{name = <<"URL">>, attrs = [], |
263 |
|
children = [{xmlcdata, Value}]}; |
264 |
|
ldap_attribute_to_vcard(vCard, {<<"desc">>, Value}) -> |
265 |
:-( |
#xmlel{name = <<"DESC">>, attrs = [], |
266 |
|
children = [{xmlcdata, Value}]}; |
267 |
|
ldap_attribute_to_vcard(vCard, {<<"role">>, Value}) -> |
268 |
:-( |
#xmlel{name = <<"ROLE">>, attrs = [], |
269 |
|
children = [{xmlcdata, Value}]}; |
270 |
|
ldap_attribute_to_vcard(vCard, {<<"tel">>, Value}) -> |
271 |
:-( |
#xmlel{name = <<"TEL">>, attrs = [], |
272 |
|
children = |
273 |
|
[#xmlel{name = <<"VOICE">>, attrs = [], children = []}, |
274 |
|
#xmlel{name = <<"WORK">>, attrs = [], children = []}, |
275 |
|
#xmlel{name = <<"NUMBER">>, attrs = [], |
276 |
|
children = [{xmlcdata, Value}]}]}; |
277 |
|
ldap_attribute_to_vcard(vCard, {<<"email">>, Value}) -> |
278 |
:-( |
#xmlel{name = <<"EMAIL">>, attrs = [], |
279 |
|
children = |
280 |
|
[#xmlel{name = <<"INTERNET">>, attrs = [], |
281 |
|
children = []}, |
282 |
|
#xmlel{name = <<"PREF">>, attrs = [], children = []}, |
283 |
|
#xmlel{name = <<"USERID">>, attrs = [], |
284 |
|
children = [{xmlcdata, Value}]}]}; |
285 |
|
ldap_attribute_to_vcard(vCard, {<<"photo">>, Value}) -> |
286 |
:-( |
#xmlel{name = <<"PHOTO">>, attrs = [], |
287 |
|
children = |
288 |
|
[#xmlel{name = <<"TYPE">>, attrs = [], |
289 |
|
children = [{xmlcdata, <<"image/jpeg">>}]}, |
290 |
|
#xmlel{name = <<"BINVAL">>, attrs = [], |
291 |
|
children = [{xmlcdata, jlib:encode_base64(Value)}]}]}; |
292 |
|
ldap_attribute_to_vcard(vCardN, |
293 |
|
{<<"family">>, Value}) -> |
294 |
:-( |
#xmlel{name = <<"FAMILY">>, attrs = [], |
295 |
|
children = [{xmlcdata, Value}]}; |
296 |
|
ldap_attribute_to_vcard(vCardN, {<<"given">>, Value}) -> |
297 |
:-( |
#xmlel{name = <<"GIVEN">>, attrs = [], |
298 |
|
children = [{xmlcdata, Value}]}; |
299 |
|
ldap_attribute_to_vcard(vCardN, |
300 |
|
{<<"middle">>, Value}) -> |
301 |
:-( |
#xmlel{name = <<"MIDDLE">>, attrs = [], |
302 |
|
children = [{xmlcdata, Value}]}; |
303 |
|
ldap_attribute_to_vcard(vCardO, |
304 |
|
{<<"orgname">>, Value}) -> |
305 |
:-( |
#xmlel{name = <<"ORGNAME">>, attrs = [], |
306 |
|
children = [{xmlcdata, Value}]}; |
307 |
|
ldap_attribute_to_vcard(vCardO, |
308 |
|
{<<"orgunit">>, Value}) -> |
309 |
:-( |
#xmlel{name = <<"ORGUNIT">>, attrs = [], |
310 |
|
children = [{xmlcdata, Value}]}; |
311 |
|
ldap_attribute_to_vcard(vCardA, |
312 |
|
{<<"locality">>, Value}) -> |
313 |
:-( |
#xmlel{name = <<"LOCALITY">>, attrs = [], |
314 |
|
children = [{xmlcdata, Value}]}; |
315 |
|
ldap_attribute_to_vcard(vCardA, |
316 |
|
{<<"street">>, Value}) -> |
317 |
:-( |
#xmlel{name = <<"STREET">>, attrs = [], |
318 |
|
children = [{xmlcdata, Value}]}; |
319 |
|
ldap_attribute_to_vcard(vCardA, {<<"ctry">>, Value}) -> |
320 |
:-( |
#xmlel{name = <<"CTRY">>, attrs = [], |
321 |
|
children = [{xmlcdata, Value}]}; |
322 |
|
ldap_attribute_to_vcard(vCardA, |
323 |
|
{<<"region">>, Value}) -> |
324 |
:-( |
#xmlel{name = <<"REGION">>, attrs = [], |
325 |
|
children = [{xmlcdata, Value}]}; |
326 |
|
ldap_attribute_to_vcard(vCardA, {<<"pcode">>, Value}) -> |
327 |
:-( |
#xmlel{name = <<"PCODE">>, attrs = [], |
328 |
|
children = [{xmlcdata, Value}]}; |
329 |
:-( |
ldap_attribute_to_vcard(_, _) -> none. |
330 |
|
|
331 |
|
search_internal(_, []) -> |
332 |
:-( |
[]; |
333 |
|
search_internal(State, Data) -> |
334 |
:-( |
Base = State#state.base, |
335 |
:-( |
SearchFilter = State#state.search_filter, |
336 |
:-( |
EldapID = State#state.eldap_id, |
337 |
:-( |
UIDs = State#state.uids, |
338 |
:-( |
Limit = State#state.matches, |
339 |
:-( |
ReportedAttrs = State#state.search_reported_attrs, |
340 |
:-( |
Op = State#state.search_operator, |
341 |
:-( |
Filter = eldap:'and'([SearchFilter, eldap_utils:make_filter(Data, UIDs, Op)]), |
342 |
:-( |
E = eldap_pool_search(EldapID, Base, Filter, State#state.deref, ReportedAttrs, error), |
343 |
:-( |
case E of |
344 |
|
error -> |
345 |
:-( |
error; |
346 |
|
E -> |
347 |
:-( |
Limited = limited_results(E, Limit), |
348 |
:-( |
search_items(Limited, State) |
349 |
|
end. |
350 |
|
|
351 |
|
limited_results(E, Limit) when length(E) > Limit -> |
352 |
:-( |
lists:sublist(E, Limit); |
353 |
|
limited_results(E, _) when not is_list(E) -> |
354 |
:-( |
[E]; |
355 |
|
limited_results(E, _) -> |
356 |
:-( |
E. |
357 |
|
|
358 |
|
search_items(Entries, State) -> |
359 |
:-( |
lists:flatmap(fun(#eldap_entry{attributes = Attrs}) -> attrs_to_item(Attrs, State) end, |
360 |
|
Entries). |
361 |
|
|
362 |
|
attrs_to_item(Attrs, #state{uids = UIDs} = State) -> |
363 |
:-( |
case eldap_utils:find_ldap_attrs(UIDs, Attrs) of |
364 |
|
{U, UIDAttrFormat} -> |
365 |
:-( |
case eldap_utils:get_user_part(U, UIDAttrFormat) of |
366 |
|
{ok, Username} -> |
367 |
:-( |
make_user_item_if_exists(Username, Attrs, State); |
368 |
:-( |
_ -> [] |
369 |
|
end; |
370 |
:-( |
<<"">> -> [] |
371 |
|
end. |
372 |
|
|
373 |
|
make_user_item_if_exists(Username, Attrs, |
374 |
|
#state{serverhost = LServer, search_reported = SearchReported, |
375 |
|
vcard_map = VCardMap, binary_search_fields = BinFields}) -> |
376 |
:-( |
JID = jid:make_bare(Username, LServer), |
377 |
:-( |
case ejabberd_auth:does_user_exist(JID) of |
378 |
|
true -> |
379 |
:-( |
RFields = lists:map(fun ({_, VCardName}) -> |
380 |
:-( |
{VCardName, map_vcard_attr(VCardName, Attrs, VCardMap, |
381 |
|
{Username, LServer})} |
382 |
|
end, |
383 |
|
SearchReported), |
384 |
:-( |
[[?FIELD(<<"jid">>, <<Username/binary, "@", LServer/binary>>)] ++ |
385 |
:-( |
[?FIELD(Name, search_item_value(Name, Value, BinFields)) || |
386 |
:-( |
{Name, Value} <- RFields]]; |
387 |
:-( |
_ -> [] |
388 |
|
end. |
389 |
|
|
390 |
|
%%%----------------------- |
391 |
|
%%% Auxiliary functions. |
392 |
|
%%%----------------------- |
393 |
|
search_item_value(Name, Value, BinaryFields) -> |
394 |
:-( |
case lists:member(Name, BinaryFields) of |
395 |
:-( |
true -> jlib:encode_base64(Value); |
396 |
:-( |
false -> Value |
397 |
|
end. |
398 |
|
|
399 |
|
map_vcard_attr(VCardName, Attributes, Pattern, UD) -> |
400 |
:-( |
Res = lists:filter(fun ({Name, _, _}) -> |
401 |
:-( |
eldap_utils:case_insensitive_match(Name, |
402 |
|
VCardName) |
403 |
|
end, |
404 |
|
Pattern), |
405 |
:-( |
case Res of |
406 |
|
[{_, Str, Attrs}] -> |
407 |
:-( |
process_pattern(Str, UD, |
408 |
:-( |
[eldap_utils:get_ldap_attr(X, Attributes) |
409 |
:-( |
|| X <- Attrs]); |
410 |
:-( |
_ -> <<"">> |
411 |
|
end. |
412 |
|
|
413 |
|
process_pattern(Str, {User, Domain}, AttrValues) -> |
414 |
:-( |
eldap_filter:do_sub(Str, |
415 |
|
[{<<"%u">>, User}, {<<"%d">>, Domain}] ++ |
416 |
:-( |
[{<<"%s">>, V, 1} || V <- AttrValues]). |
417 |
|
|
418 |
|
get_state(HostType, LServer) -> |
419 |
:-( |
Key = config_key(HostType, LServer), |
420 |
:-( |
case persistent_term:get(Key, undefined) of |
421 |
|
undefined -> |
422 |
:-( |
State = create_state(HostType, LServer), |
423 |
:-( |
persistent_term:put(Key, State), |
424 |
:-( |
State; |
425 |
|
State -> |
426 |
:-( |
State |
427 |
|
end. |
428 |
|
|
429 |
|
create_state(HostType, LServer) -> |
430 |
:-( |
Opts = gen_mod:get_loaded_module_opts(HostType, mod_vcard), |
431 |
:-( |
Matches = gen_mod:get_opt(matches, Opts), |
432 |
:-( |
Host = gen_mod:get_opt(host, Opts), |
433 |
:-( |
LDAPOpts = gen_mod:get_opt(ldap, Opts), |
434 |
:-( |
#{pool_tag := PoolTag, |
435 |
|
base := Base, |
436 |
|
deref := Deref, |
437 |
|
uids := RawUIDs, |
438 |
|
filter := RawUserFilter, |
439 |
|
vcard_map := VCardMap, |
440 |
|
search_fields := SearchFields, |
441 |
|
search_reported := SearchReported, |
442 |
|
search_operator := SearchOperator, |
443 |
|
binary_search_fields := BinaryFields} = LDAPOpts, |
444 |
:-( |
MyHost = mongoose_subdomain_utils:get_fqdn(Host, LServer), |
445 |
:-( |
DerefAliases = eldap_utils:deref_aliases(Deref), |
446 |
:-( |
UIDs = eldap_utils:uids_domain_subst(LServer, RawUIDs), |
447 |
:-( |
UserFilter = eldap_utils:process_user_filter(UIDs, RawUserFilter), |
448 |
:-( |
{ok, SearchFilter} = eldap_filter:parse(eldap_utils:get_search_filter(UserFilter)), |
449 |
|
|
450 |
:-( |
UIDAttrs = lists:map(fun({UID, _}) -> UID; |
451 |
:-( |
({UID}) -> UID end, UIDs), |
452 |
:-( |
VCardMapAttrs = lists:usort(lists:append([A || {_, _, A} <- VCardMap]) |
453 |
|
++ UIDAttrs), |
454 |
:-( |
SearchReportedAttrs = lists:usort(lists:flatmap( |
455 |
|
fun ({_, N}) -> |
456 |
:-( |
case lists:keysearch(N, 1, VCardMap) of |
457 |
|
{value, {_, _, L}} -> |
458 |
:-( |
L; |
459 |
:-( |
_ -> [] |
460 |
|
end |
461 |
|
end, |
462 |
|
SearchReported) ++ UIDAttrs), |
463 |
:-( |
#state{serverhost = LServer, |
464 |
|
myhost = MyHost, |
465 |
|
eldap_id = {HostType, PoolTag}, |
466 |
|
base = Base, |
467 |
|
deref = DerefAliases, |
468 |
|
uids = UIDs, vcard_map = VCardMap, |
469 |
|
vcard_map_attrs = VCardMapAttrs, |
470 |
|
user_filter = UserFilter, search_filter = SearchFilter, |
471 |
|
search_fields = SearchFields, |
472 |
|
binary_search_fields = BinaryFields, |
473 |
|
search_reported = SearchReported, |
474 |
|
search_reported_attrs = SearchReportedAttrs, |
475 |
|
search_operator = SearchOperator, |
476 |
|
matches = Matches}. |
477 |
|
|
478 |
|
clear_persistent_term(HostType) -> |
479 |
:-( |
Terms = persistent_term:get(), |
480 |
:-( |
States = lists:filter(fun({K, _V}) -> is_host_type_config_key(HostType, K) end, Terms), |
481 |
:-( |
[persistent_term:erase(Key) || {Key, _V} <- States]. |
482 |
|
|
483 |
|
is_host_type_config_key(HostType, {?MODULE, HostType, _LServer}) -> |
484 |
:-( |
true; |
485 |
|
is_host_type_config_key(_HT, _K) -> |
486 |
:-( |
false. |
487 |
|
|
488 |
|
config_key(HostType, LServer) -> |
489 |
:-( |
{?MODULE, HostType, LServer}. |