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 |
|
%%TODO gen_server is created only to store the state |
27 |
|
%% and create/destroy pool, should it be replaced ? |
28 |
|
|
29 |
|
-module(mod_vcard_ldap). |
30 |
|
-author('alexey@process-one.net'). |
31 |
|
|
32 |
|
-behaviour(mod_vcard_backend). |
33 |
|
|
34 |
|
%% mod_vcards callbacks |
35 |
|
-export([init/2, |
36 |
|
tear_down/1, |
37 |
|
remove_user/3, |
38 |
|
get_vcard/3, |
39 |
|
set_vcard/5, |
40 |
|
search/3, |
41 |
|
search_fields/2, |
42 |
|
search_reported_fields/3]). |
43 |
|
|
44 |
|
-include("eldap.hrl"). |
45 |
|
-include("mod_vcard.hrl"). |
46 |
|
-include("jlib.hrl"). |
47 |
|
|
48 |
|
-record(state, |
49 |
|
{serverhost = <<>> :: binary(), |
50 |
|
myhost = <<>> :: binary(), |
51 |
|
eldap_id :: eldap_utils:eldap_id(), |
52 |
|
base = <<>> :: binary(), |
53 |
|
password = <<>> :: binary(), |
54 |
|
uids = [] :: [{binary()} | {binary(), binary()}], |
55 |
|
vcard_map = [] :: [{binary(), binary(), [binary()]}], |
56 |
|
vcard_map_attrs = [] :: [binary()], |
57 |
|
user_filter = <<>> :: binary(), |
58 |
|
search_filter :: eldap:filter(), |
59 |
|
search_fields = [] :: [{binary(), binary()}], |
60 |
|
search_reported = [] :: [{binary(), binary()}], |
61 |
|
search_reported_attrs = [] :: [binary()], |
62 |
|
search_operator :: 'or' | 'and', |
63 |
|
binary_search_fields :: [binary()], |
64 |
|
deref = neverDerefAliases :: eldap_utils:deref(), |
65 |
|
matches = 0 :: non_neg_integer() | infinity}). |
66 |
|
|
67 |
|
-define(VCARD_MAP, |
68 |
|
[{<<"NICKNAME">>, <<"%u">>, []}, |
69 |
|
{<<"FN">>, <<"%s">>, [<<"displayName">>]}, |
70 |
|
{<<"FAMILY">>, <<"%s">>, [<<"sn">>]}, |
71 |
|
{<<"GIVEN">>, <<"%s">>, [<<"givenName">>]}, |
72 |
|
{<<"MIDDLE">>, <<"%s">>, [<<"initials">>]}, |
73 |
|
{<<"ORGNAME">>, <<"%s">>, [<<"o">>]}, |
74 |
|
{<<"ORGUNIT">>, <<"%s">>, [<<"ou">>]}, |
75 |
|
{<<"CTRY">>, <<"%s">>, [<<"c">>]}, |
76 |
|
{<<"LOCALITY">>, <<"%s">>, [<<"l">>]}, |
77 |
|
{<<"STREET">>, <<"%s">>, [<<"street">>]}, |
78 |
|
{<<"REGION">>, <<"%s">>, [<<"st">>]}, |
79 |
|
{<<"PCODE">>, <<"%s">>, [<<"postalCode">>]}, |
80 |
|
{<<"TITLE">>, <<"%s">>, [<<"title">>]}, |
81 |
|
{<<"URL">>, <<"%s">>, [<<"labeleduri">>]}, |
82 |
|
{<<"DESC">>, <<"%s">>, [<<"description">>]}, |
83 |
|
{<<"TEL">>, <<"%s">>, [<<"telephoneNumber">>]}, |
84 |
|
{<<"EMAIL">>, <<"%s">>, [<<"mail">>]}, |
85 |
|
{<<"BDAY">>, <<"%s">>, [<<"birthDay">>]}, |
86 |
|
{<<"ROLE">>, <<"%s">>, [<<"employeeType">>]}, |
87 |
|
{<<"PHOTO">>, <<"%s">>, [<<"jpegPhoto">>]}]). |
88 |
|
|
89 |
|
-define(SEARCH_FIELDS, |
90 |
|
[{<<"User">>, <<"%u">>}, |
91 |
|
{<<"Full Name">>, <<"displayName">>}, |
92 |
|
{<<"Given Name">>, <<"givenName">>}, |
93 |
|
{<<"Middle Name">>, <<"initials">>}, |
94 |
|
{<<"Family Name">>, <<"sn">>}, |
95 |
|
{<<"Nickname">>, <<"%u">>}, |
96 |
|
{<<"Birthday">>, <<"birthDay">>}, |
97 |
|
{<<"Country">>, <<"c">>}, {<<"City">>, <<"l">>}, |
98 |
|
{<<"Email">>, <<"mail">>}, |
99 |
|
{<<"Organization Name">>, <<"o">>}, |
100 |
|
{<<"Organization Unit">>, <<"ou">>}]). |
101 |
|
|
102 |
|
-define(SEARCH_REPORTED, |
103 |
|
[{<<"Full Name">>, <<"FN">>}, |
104 |
|
{<<"Given Name">>, <<"FIRST">>}, |
105 |
|
{<<"Middle Name">>, <<"MIDDLE">>}, |
106 |
|
{<<"Family Name">>, <<"LAST">>}, |
107 |
|
{<<"Nickname">>, <<"NICK">>}, |
108 |
|
{<<"Birthday">>, <<"BDAY">>}, |
109 |
|
{<<"Country">>, <<"CTRY">>}, |
110 |
|
{<<"City">>, <<"LOCALITY">>}, |
111 |
|
{<<"Email">>, <<"EMAIL">>}, |
112 |
|
{<<"Organization Name">>, <<"ORGNAME">>}, |
113 |
|
{<<"Organization Unit">>, <<"ORGUNIT">>}]). |
114 |
|
|
115 |
|
|
116 |
|
|
117 |
|
%%-------------------------------------------------------------------- |
118 |
|
%% mod_vcards callbacks |
119 |
|
%%-------------------------------------------------------------------- |
120 |
|
|
121 |
|
init(_HostType, _Opts) -> |
122 |
:-( |
ok. |
123 |
|
|
124 |
|
tear_down(_HostType) -> |
125 |
:-( |
ok. |
126 |
|
|
127 |
|
remove_user(_HostType, _LUser, _LServer) -> |
128 |
|
%% no need to handle this - in ldap |
129 |
|
%% removing user = delete all user info |
130 |
:-( |
ok. |
131 |
|
|
132 |
|
get_vcard(HostType, LUser, LServer) -> |
133 |
:-( |
State = get_state(HostType, LServer), |
134 |
:-( |
LServer = State#state.serverhost, |
135 |
:-( |
JID = jid:make(LUser, LServer, <<>>), |
136 |
:-( |
case ejabberd_auth:does_user_exist(JID) of |
137 |
|
true -> |
138 |
:-( |
VCardMap = State#state.vcard_map, |
139 |
:-( |
case find_ldap_user(LUser, State) of |
140 |
|
#eldap_entry{attributes = Attributes} -> |
141 |
:-( |
Vcard = ldap_attributes_to_vcard(Attributes, VCardMap, {LUser, LServer}), |
142 |
:-( |
{ok, Vcard}; |
143 |
|
_ -> |
144 |
:-( |
{ok, []} |
145 |
|
end; |
146 |
|
_ -> |
147 |
:-( |
{ok, []} |
148 |
|
end. |
149 |
|
|
150 |
|
set_vcard(_HostType, _User, _LServer, _VCard, _VCardSearch) -> |
151 |
:-( |
{error, mongoose_xmpp_errors:not_allowed()}. |
152 |
|
|
153 |
|
search(HostType, LServer, Data) -> |
154 |
:-( |
State = get_state(HostType, LServer), |
155 |
:-( |
search_internal(State, Data). |
156 |
|
|
157 |
|
search_fields(HostType, LServer) -> |
158 |
:-( |
State = get_state(HostType, LServer), |
159 |
:-( |
State#state.search_fields. |
160 |
|
|
161 |
|
search_reported_fields(HostType, LServer, Lang) -> |
162 |
:-( |
State = get_state(HostType, LServer), |
163 |
:-( |
SearchReported = State#state.search_reported, |
164 |
:-( |
#xmlel{name = <<"reported">>, attrs = [], |
165 |
|
children = |
166 |
|
[?TLFIELD(<<"text-single">>, <<"Jabber ID">>, |
167 |
|
<<"jid">>)] |
168 |
|
++ |
169 |
|
lists:map(fun ({Name, Value}) -> |
170 |
:-( |
?TLFIELD(<<"text-single">>, Name, |
171 |
|
Value) |
172 |
|
end, |
173 |
|
SearchReported)}. |
174 |
|
|
175 |
|
%%-------------------------------------------------------------------- |
176 |
|
%% Internal |
177 |
|
%%-------------------------------------------------------------------- |
178 |
|
find_ldap_user(User, State) -> |
179 |
:-( |
Base = State#state.base, |
180 |
:-( |
RFC2254Filter = State#state.user_filter, |
181 |
:-( |
EldapID = State#state.eldap_id, |
182 |
:-( |
VCardAttrs = State#state.vcard_map_attrs, |
183 |
:-( |
case eldap_filter:parse(RFC2254Filter, [{<<"%u">>, User}]) of |
184 |
|
{ok, EldapFilter} -> |
185 |
:-( |
Res = eldap_pool_search(EldapID, Base, EldapFilter, State#state.deref, VCardAttrs, false), |
186 |
:-( |
case Res of |
187 |
|
[H | _] -> |
188 |
:-( |
H; |
189 |
|
_ -> |
190 |
:-( |
Res |
191 |
|
end; |
192 |
:-( |
_ -> false |
193 |
|
end. |
194 |
|
|
195 |
|
eldap_pool_search(EldapID, Base, EldapFilter, Deref, Attrs, NoResultRes) -> |
196 |
:-( |
SearchOpts = search_opts(Base, EldapFilter, Deref, Attrs), |
197 |
:-( |
case eldap_pool:search(EldapID, SearchOpts) of |
198 |
:-( |
#eldap_search_result{entries = E} -> E; |
199 |
:-( |
_ -> NoResultRes |
200 |
|
end. |
201 |
|
|
202 |
|
search_opts(Base, EldapFilter, Deref, Attrs) -> |
203 |
:-( |
[{base, Base}, {filter, EldapFilter}, |
204 |
|
{deref, Deref}, {attributes, Attrs}]. |
205 |
|
|
206 |
|
ldap_attributes_to_vcard(Attributes, VCardMap, UD) -> |
207 |
:-( |
Attrs = lists:map(fun ({VCardName, _, _}) -> |
208 |
:-( |
{jid:str_tolower(VCardName), |
209 |
|
map_vcard_attr(VCardName, Attributes, VCardMap, |
210 |
|
UD)} |
211 |
|
end, |
212 |
|
VCardMap), |
213 |
:-( |
Elts = [ldap_attribute_to_vcard(vCard, Attr) |
214 |
:-( |
|| Attr <- Attrs], |
215 |
:-( |
NElts = [ldap_attribute_to_vcard(vCardN, Attr) |
216 |
:-( |
|| Attr <- Attrs], |
217 |
:-( |
OElts = [ldap_attribute_to_vcard(vCardO, Attr) |
218 |
:-( |
|| Attr <- Attrs], |
219 |
:-( |
AElts = [ldap_attribute_to_vcard(vCardA, Attr) |
220 |
:-( |
|| Attr <- Attrs], |
221 |
:-( |
[#xmlel{name = <<"vCard">>, |
222 |
|
attrs = [{<<"xmlns">>, ?NS_VCARD}], |
223 |
|
children = |
224 |
:-( |
lists:append([X || X <- Elts, X /= none], |
225 |
|
[#xmlel{name = <<"N">>, attrs = [], |
226 |
:-( |
children = [X || X <- NElts, X /= none]}, |
227 |
|
#xmlel{name = <<"ORG">>, attrs = [], |
228 |
:-( |
children = [X || X <- OElts, X /= none]}, |
229 |
|
#xmlel{name = <<"ADR">>, attrs = [], |
230 |
|
children = |
231 |
:-( |
[X || X <- AElts, X /= none]}])}]. |
232 |
|
|
233 |
|
ldap_attribute_to_vcard(vCard, {<<"fn">>, Value}) -> |
234 |
:-( |
#xmlel{name = <<"FN">>, attrs = [], |
235 |
|
children = [{xmlcdata, Value}]}; |
236 |
|
ldap_attribute_to_vcard(vCard, |
237 |
|
{<<"nickname">>, Value}) -> |
238 |
:-( |
#xmlel{name = <<"NICKNAME">>, attrs = [], |
239 |
|
children = [{xmlcdata, Value}]}; |
240 |
|
ldap_attribute_to_vcard(vCard, {<<"title">>, Value}) -> |
241 |
:-( |
#xmlel{name = <<"TITLE">>, attrs = [], |
242 |
|
children = [{xmlcdata, Value}]}; |
243 |
|
ldap_attribute_to_vcard(vCard, {<<"bday">>, Value}) -> |
244 |
:-( |
#xmlel{name = <<"BDAY">>, attrs = [], |
245 |
|
children = [{xmlcdata, Value}]}; |
246 |
|
ldap_attribute_to_vcard(vCard, {<<"url">>, Value}) -> |
247 |
:-( |
#xmlel{name = <<"URL">>, attrs = [], |
248 |
|
children = [{xmlcdata, Value}]}; |
249 |
|
ldap_attribute_to_vcard(vCard, {<<"desc">>, Value}) -> |
250 |
:-( |
#xmlel{name = <<"DESC">>, attrs = [], |
251 |
|
children = [{xmlcdata, Value}]}; |
252 |
|
ldap_attribute_to_vcard(vCard, {<<"role">>, Value}) -> |
253 |
:-( |
#xmlel{name = <<"ROLE">>, attrs = [], |
254 |
|
children = [{xmlcdata, Value}]}; |
255 |
|
ldap_attribute_to_vcard(vCard, {<<"tel">>, Value}) -> |
256 |
:-( |
#xmlel{name = <<"TEL">>, attrs = [], |
257 |
|
children = |
258 |
|
[#xmlel{name = <<"VOICE">>, attrs = [], children = []}, |
259 |
|
#xmlel{name = <<"WORK">>, attrs = [], children = []}, |
260 |
|
#xmlel{name = <<"NUMBER">>, attrs = [], |
261 |
|
children = [{xmlcdata, Value}]}]}; |
262 |
|
ldap_attribute_to_vcard(vCard, {<<"email">>, Value}) -> |
263 |
:-( |
#xmlel{name = <<"EMAIL">>, attrs = [], |
264 |
|
children = |
265 |
|
[#xmlel{name = <<"INTERNET">>, attrs = [], |
266 |
|
children = []}, |
267 |
|
#xmlel{name = <<"PREF">>, attrs = [], children = []}, |
268 |
|
#xmlel{name = <<"USERID">>, attrs = [], |
269 |
|
children = [{xmlcdata, Value}]}]}; |
270 |
|
ldap_attribute_to_vcard(vCard, {<<"photo">>, Value}) -> |
271 |
:-( |
#xmlel{name = <<"PHOTO">>, attrs = [], |
272 |
|
children = |
273 |
|
[#xmlel{name = <<"TYPE">>, attrs = [], |
274 |
|
children = [{xmlcdata, <<"image/jpeg">>}]}, |
275 |
|
#xmlel{name = <<"BINVAL">>, attrs = [], |
276 |
|
children = [{xmlcdata, jlib:encode_base64(Value)}]}]}; |
277 |
|
ldap_attribute_to_vcard(vCardN, |
278 |
|
{<<"family">>, Value}) -> |
279 |
:-( |
#xmlel{name = <<"FAMILY">>, attrs = [], |
280 |
|
children = [{xmlcdata, Value}]}; |
281 |
|
ldap_attribute_to_vcard(vCardN, {<<"given">>, Value}) -> |
282 |
:-( |
#xmlel{name = <<"GIVEN">>, attrs = [], |
283 |
|
children = [{xmlcdata, Value}]}; |
284 |
|
ldap_attribute_to_vcard(vCardN, |
285 |
|
{<<"middle">>, Value}) -> |
286 |
:-( |
#xmlel{name = <<"MIDDLE">>, attrs = [], |
287 |
|
children = [{xmlcdata, Value}]}; |
288 |
|
ldap_attribute_to_vcard(vCardO, |
289 |
|
{<<"orgname">>, Value}) -> |
290 |
:-( |
#xmlel{name = <<"ORGNAME">>, attrs = [], |
291 |
|
children = [{xmlcdata, Value}]}; |
292 |
|
ldap_attribute_to_vcard(vCardO, |
293 |
|
{<<"orgunit">>, Value}) -> |
294 |
:-( |
#xmlel{name = <<"ORGUNIT">>, attrs = [], |
295 |
|
children = [{xmlcdata, Value}]}; |
296 |
|
ldap_attribute_to_vcard(vCardA, |
297 |
|
{<<"locality">>, Value}) -> |
298 |
:-( |
#xmlel{name = <<"LOCALITY">>, attrs = [], |
299 |
|
children = [{xmlcdata, Value}]}; |
300 |
|
ldap_attribute_to_vcard(vCardA, |
301 |
|
{<<"street">>, Value}) -> |
302 |
:-( |
#xmlel{name = <<"STREET">>, attrs = [], |
303 |
|
children = [{xmlcdata, Value}]}; |
304 |
|
ldap_attribute_to_vcard(vCardA, {<<"ctry">>, Value}) -> |
305 |
:-( |
#xmlel{name = <<"CTRY">>, attrs = [], |
306 |
|
children = [{xmlcdata, Value}]}; |
307 |
|
ldap_attribute_to_vcard(vCardA, |
308 |
|
{<<"region">>, Value}) -> |
309 |
:-( |
#xmlel{name = <<"REGION">>, attrs = [], |
310 |
|
children = [{xmlcdata, Value}]}; |
311 |
|
ldap_attribute_to_vcard(vCardA, {<<"pcode">>, Value}) -> |
312 |
:-( |
#xmlel{name = <<"PCODE">>, attrs = [], |
313 |
|
children = [{xmlcdata, Value}]}; |
314 |
:-( |
ldap_attribute_to_vcard(_, _) -> none. |
315 |
|
|
316 |
|
search_internal(_, []) -> |
317 |
:-( |
[]; |
318 |
|
search_internal(State, Data) -> |
319 |
:-( |
Base = State#state.base, |
320 |
:-( |
SearchFilter = State#state.search_filter, |
321 |
:-( |
EldapID = State#state.eldap_id, |
322 |
:-( |
UIDs = State#state.uids, |
323 |
:-( |
Limit = State#state.matches, |
324 |
:-( |
ReportedAttrs = State#state.search_reported_attrs, |
325 |
:-( |
Op = State#state.search_operator, |
326 |
:-( |
Filter = eldap:'and'([SearchFilter, eldap_utils:make_filter(Data, UIDs, Op)]), |
327 |
:-( |
E = eldap_pool_search(EldapID, Base, Filter, State#state.deref, ReportedAttrs, error), |
328 |
:-( |
case E of |
329 |
|
error -> |
330 |
:-( |
error; |
331 |
|
E -> |
332 |
:-( |
Limited = limited_results(E, Limit), |
333 |
:-( |
search_items(Limited, State) |
334 |
|
end. |
335 |
|
|
336 |
|
limited_results(E, Limit) when length(E) > Limit -> |
337 |
:-( |
lists:sublist(E, Limit); |
338 |
|
limited_results(E, _) when not is_list(E) -> |
339 |
:-( |
[E]; |
340 |
|
limited_results(E, _) -> |
341 |
:-( |
E. |
342 |
|
|
343 |
|
search_items(Entries, State) -> |
344 |
:-( |
lists:flatmap(fun(#eldap_entry{attributes = Attrs}) -> attrs_to_item_xml(Attrs, State) end, |
345 |
|
Entries). |
346 |
|
|
347 |
|
attrs_to_item_xml(Attrs, #state{uids = UIDs} = State) -> |
348 |
:-( |
case eldap_utils:find_ldap_attrs(UIDs, Attrs) of |
349 |
|
{U, UIDAttrFormat} -> |
350 |
:-( |
case eldap_utils:get_user_part(U, UIDAttrFormat) of |
351 |
|
{ok, Username} -> |
352 |
:-( |
make_user_item_if_exists(Username, Attrs, State); |
353 |
:-( |
_ -> [] |
354 |
|
end; |
355 |
:-( |
<<"">> -> [] |
356 |
|
end. |
357 |
|
|
358 |
|
make_user_item_if_exists(Username, Attrs, |
359 |
|
#state{serverhost = LServer, search_reported = SearchReported, |
360 |
|
vcard_map = VCardMap, binary_search_fields = BinFields}) -> |
361 |
:-( |
JID = jid:make(Username, LServer, <<>>), |
362 |
:-( |
case ejabberd_auth:does_user_exist(JID) of |
363 |
|
true -> |
364 |
:-( |
RFields = lists:map(fun ({_, VCardName}) -> |
365 |
:-( |
{VCardName, map_vcard_attr(VCardName, Attrs, VCardMap, |
366 |
|
{Username, LServer})} |
367 |
|
end, |
368 |
|
SearchReported), |
369 |
:-( |
Result = [?FIELD(<<"jid">>, <<Username/binary, "@", LServer/binary>>)] ++ |
370 |
:-( |
[?FIELD(Name, search_item_value(Name, Value, BinFields)) || {Name, Value} <- RFields], |
371 |
:-( |
[#xmlel{name = <<"item">>, attrs = [], children = Result}]; |
372 |
:-( |
_ -> [] |
373 |
|
end. |
374 |
|
|
375 |
|
%%%----------------------- |
376 |
|
%%% Auxiliary functions. |
377 |
|
%%%----------------------- |
378 |
|
search_item_value(Name, Value, BinaryFields) -> |
379 |
:-( |
case lists:member(Name, BinaryFields) of |
380 |
:-( |
true -> jlib:encode_base64(Value); |
381 |
:-( |
false -> Value |
382 |
|
end. |
383 |
|
|
384 |
|
map_vcard_attr(VCardName, Attributes, Pattern, UD) -> |
385 |
:-( |
Res = lists:filter(fun ({Name, _, _}) -> |
386 |
:-( |
eldap_utils:case_insensitive_match(Name, |
387 |
|
VCardName) |
388 |
|
end, |
389 |
|
Pattern), |
390 |
:-( |
case Res of |
391 |
|
[{_, Str, Attrs}] -> |
392 |
:-( |
process_pattern(Str, UD, |
393 |
:-( |
[eldap_utils:get_ldap_attr(X, Attributes) |
394 |
:-( |
|| X <- Attrs]); |
395 |
:-( |
_ -> <<"">> |
396 |
|
end. |
397 |
|
|
398 |
|
process_pattern(Str, {User, Domain}, AttrValues) -> |
399 |
:-( |
eldap_filter:do_sub(Str, |
400 |
|
[{<<"%u">>, User}, {<<"%d">>, Domain}] ++ |
401 |
:-( |
[{<<"%s">>, V, 1} || V <- AttrValues]). |
402 |
|
|
403 |
|
get_state(HostType, LServer) -> |
404 |
:-( |
Opts = gen_mod:get_loaded_module_opts(HostType, mod_vcard), |
405 |
:-( |
MyHost = gen_mod:get_opt_subhost(LServer, Opts, mod_vcard:default_host()), |
406 |
:-( |
Matches = eldap_utils:get_mod_opt(matches, Opts, |
407 |
:-( |
fun(infinity) -> infinity; |
408 |
:-( |
(I) when is_integer(I), I>=0 -> I |
409 |
|
end, 30), |
410 |
:-( |
EldapID = eldap_utils:get_mod_opt(ldap_pool_tag, Opts, |
411 |
:-( |
fun(A) when is_atom(A) -> A end, default), |
412 |
:-( |
Base = eldap_utils:get_base(Opts), |
413 |
:-( |
DerefAliases = eldap_utils:get_deref_aliases(Opts), |
414 |
:-( |
UIDs = eldap_utils:get_uids(LServer, Opts), |
415 |
:-( |
UserFilter = eldap_utils:get_user_filter(UIDs, Opts), |
416 |
:-( |
{ok, SearchFilter} = |
417 |
|
eldap_filter:parse(eldap_utils:get_search_filter(UserFilter)), |
418 |
:-( |
VCardMap = eldap_utils:get_mod_opt(ldap_vcard_map, Opts, |
419 |
|
fun(Ls) -> |
420 |
:-( |
lists:map( |
421 |
|
fun({S, P, L}) -> |
422 |
:-( |
{iolist_to_binary(S), |
423 |
|
iolist_to_binary(P), |
424 |
:-( |
[iolist_to_binary(E) |
425 |
:-( |
|| E <- L]} |
426 |
|
end, Ls) |
427 |
|
end, ?VCARD_MAP), |
428 |
:-( |
SearchFields = eldap_utils:get_mod_opt(ldap_search_fields, Opts, |
429 |
|
fun(Ls) -> |
430 |
:-( |
[{iolist_to_binary(S), |
431 |
|
iolist_to_binary(P)} |
432 |
:-( |
|| {S, P} <- Ls] |
433 |
|
end, ?SEARCH_FIELDS), |
434 |
:-( |
SearchReported = eldap_utils:get_mod_opt(ldap_search_reported, Opts, |
435 |
|
fun(Ls) -> |
436 |
:-( |
[{iolist_to_binary(S), |
437 |
|
iolist_to_binary(P)} |
438 |
:-( |
|| {S, P} <- Ls] |
439 |
|
end, ?SEARCH_REPORTED), |
440 |
:-( |
UIDAttrs = lists:map(fun({UID, _}) -> UID; |
441 |
:-( |
({UID}) -> UID end, UIDs), |
442 |
:-( |
VCardMapAttrs = lists:usort(lists:append([A |
443 |
:-( |
|| {_, _, A} <- VCardMap]) |
444 |
|
++ UIDAttrs), |
445 |
:-( |
SearchReportedAttrs = lists:usort(lists:flatmap( |
446 |
|
fun ({_, N}) -> |
447 |
:-( |
case lists:keysearch(N, 1, VCardMap) of |
448 |
|
{value, {_, _, L}} -> |
449 |
:-( |
L; |
450 |
:-( |
_ -> [] |
451 |
|
end |
452 |
|
end, |
453 |
|
SearchReported) ++ UIDAttrs), |
454 |
:-( |
SearchOperatorFun = fun |
455 |
:-( |
('or') -> 'or'; |
456 |
:-( |
(_) -> 'and' |
457 |
|
end, |
458 |
:-( |
SearchOperator = eldap_utils:get_mod_opt(ldap_search_operator, Opts, |
459 |
|
SearchOperatorFun, 'and'), |
460 |
:-( |
BinaryFields = eldap_utils:get_mod_opt(ldap_binary_search_fields, Opts, |
461 |
:-( |
fun(X) -> X end, []), |
462 |
:-( |
#state{serverhost = LServer, |
463 |
|
myhost = MyHost, |
464 |
|
eldap_id = {HostType, EldapID}, |
465 |
|
base = Base, |
466 |
|
deref = DerefAliases, |
467 |
|
uids = UIDs, vcard_map = VCardMap, |
468 |
|
vcard_map_attrs = VCardMapAttrs, |
469 |
|
user_filter = UserFilter, search_filter = SearchFilter, |
470 |
|
search_fields = SearchFields, |
471 |
|
binary_search_fields = BinaryFields, |
472 |
|
search_reported = SearchReported, |
473 |
|
search_reported_attrs = SearchReportedAttrs, |
474 |
|
search_operator = SearchOperator, |
475 |
|
matches = Matches}. |