1 |
slords |
1.1 |
|
2 |
|
|
%%%---------------------------------------------------------------------- |
3 |
|
|
%%% File : mod_vcard_ad.erl |
4 |
|
|
%%% Author : Stanislav Bogatyrev <realloc@realloc.spb.ru> |
5 |
|
|
%%% Author : Alexey Shchepin <alexey@sevcom.net> |
6 |
|
|
%%% Author : Alex <agent_007> Gorbachenko (agent_007@immo.ru) |
7 |
|
|
%%% Purpose : |
8 |
|
|
%%% Created : 2 Jan 2003 by Alexey Shchepin <alexey@sevcom.net> |
9 |
|
|
%%% Id : $Id: mod_vcard_ad.erl 437 2005-11-19 01:20:05Z agent_007 $ |
10 |
|
|
%%%---------------------------------------------------------------------- |
11 |
|
|
|
12 |
|
|
-module(mod_vcard_ad). |
13 |
|
|
-author('realloc@realloc.spb.ru'). |
14 |
|
|
-author('alexey@sevcom.net'). |
15 |
|
|
-author('agent_007@immo.ru'). |
16 |
|
|
-vsn('$Revision: 437 $ '). |
17 |
|
|
|
18 |
|
|
-behaviour(gen_mod). |
19 |
|
|
|
20 |
|
|
-export([start/2, init/3, stop/1, |
21 |
|
|
get_sm_features/5, |
22 |
|
|
process_local_iq/3, |
23 |
|
|
process_sm_iq/3, |
24 |
|
|
remove_user/1]). |
25 |
|
|
|
26 |
|
|
-include("ejabberd.hrl"). |
27 |
|
|
-include("eldap/eldap.hrl"). |
28 |
|
|
-include("jlib.hrl"). |
29 |
|
|
|
30 |
|
|
-define(PROCNAME, ejabberd_mod_vcard_ad). |
31 |
|
|
|
32 |
|
|
start(Host, Opts) -> |
33 |
|
|
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), |
34 |
|
|
gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD, |
35 |
|
|
?MODULE, process_local_iq, IQDisc), |
36 |
|
|
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD, |
37 |
|
|
?MODULE, process_sm_iq, IQDisc), |
38 |
|
|
ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50), |
39 |
|
|
LDAPServers = ejabberd_config:get_local_option({ad_servers, Host}), |
40 |
|
|
RootDN = ejabberd_config:get_local_option({ad_rootdn, Host}), |
41 |
|
|
Password = ejabberd_config:get_local_option({ad_password, Host}), |
42 |
|
|
eldap:start_link("mod_vcard_ad", LDAPServers, 389, RootDN, Password), |
43 |
|
|
MyHost = gen_mod:get_opt(host, Opts, "vjud." ++ Host), |
44 |
|
|
Search = gen_mod:get_opt(search, Opts, true), |
45 |
|
|
register(gen_mod:get_module_proc(Host, ?PROCNAME), |
46 |
|
|
spawn(?MODULE, init, [MyHost, Host, Search])). |
47 |
|
|
|
48 |
|
|
init(Host, ServerHost, Search) -> |
49 |
|
|
case Search of |
50 |
|
|
false -> |
51 |
|
|
loop(Host, ServerHost); |
52 |
|
|
_ -> |
53 |
|
|
ejabberd_router:register_route(Host), |
54 |
|
|
loop(Host, ServerHost) |
55 |
|
|
end. |
56 |
|
|
|
57 |
|
|
loop(Host, ServerHost) -> |
58 |
|
|
receive |
59 |
|
|
{route, From, To, Packet} -> |
60 |
|
|
case catch do_route(ServerHost, From, To, Packet) of |
61 |
|
|
{'EXIT', Reason} -> |
62 |
|
|
?ERROR_MSG("~p", [Reason]); |
63 |
|
|
_ -> |
64 |
|
|
ok |
65 |
|
|
end, |
66 |
|
|
loop(Host, ServerHost); |
67 |
|
|
stop -> |
68 |
|
|
ejabberd_router:unregister_route(Host), |
69 |
|
|
ok; |
70 |
|
|
_ -> |
71 |
|
|
loop(Host, ServerHost) |
72 |
|
|
end. |
73 |
|
|
|
74 |
|
|
stop(Host) -> |
75 |
|
|
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD), |
76 |
|
|
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD), |
77 |
|
|
ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50), |
78 |
|
|
Proc = gen_mod:get_module_proc(Host, ?PROCNAME), |
79 |
|
|
Proc ! stop, |
80 |
|
|
{wait, Proc}. |
81 |
|
|
|
82 |
|
|
get_sm_features({error, _Error} = Acc, _From, _To, _Node, _Lang) -> |
83 |
|
|
Acc; |
84 |
|
|
get_sm_features(Acc, _From, _To, Node, _Lang) -> |
85 |
|
|
case Node of |
86 |
|
|
[] -> |
87 |
|
|
case Acc of |
88 |
|
|
{result, Features} -> |
89 |
|
|
{result, [?NS_VCARD | Features]}; |
90 |
|
|
empty -> |
91 |
|
|
{result, [?NS_VCARD]} |
92 |
|
|
end; |
93 |
|
|
_ -> |
94 |
|
|
Acc |
95 |
|
|
end. |
96 |
|
|
|
97 |
|
|
process_local_iq(_From, _To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) -> |
98 |
|
|
case Type of |
99 |
|
|
set -> |
100 |
|
|
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; |
101 |
|
|
get -> |
102 |
|
|
IQ#iq{type = result, |
103 |
|
|
sub_el = [{xmlelement, "vCard", |
104 |
|
|
[{"xmlns", ?NS_VCARD}], |
105 |
|
|
[{xmlelement, "FN", [], |
106 |
|
|
[{xmlcdata, "ejabberd"}]}, |
107 |
|
|
{xmlelement, "URL", [], |
108 |
|
|
[{xmlcdata, |
109 |
|
|
"http://ejabberd.jabberstudio.org/"}]}, |
110 |
|
|
{xmlelement, "DESC", [], |
111 |
|
|
[{xmlcdata, |
112 |
|
|
translate:translate( |
113 |
|
|
Lang, |
114 |
|
|
"Erlang Jabber Server\n" |
115 |
|
|
"Copyright (c) 2002-2005 Alexey Shchepin")}]}, |
116 |
|
|
{xmlelement, "BDAY", [], |
117 |
|
|
[{xmlcdata, "2002-11-16"}]} |
118 |
|
|
]}]} |
119 |
|
|
end. |
120 |
|
|
|
121 |
|
|
find_ldap_user(Host, User) -> |
122 |
|
|
Attr = ejabberd_config:get_local_option({ad_uidattr, Host}), |
123 |
|
|
Filter = eldap:equalityMatch(Attr, User), |
124 |
|
|
Base = ejabberd_config:get_local_option({ad_base, Host}), |
125 |
|
|
case eldap:search("mod_vcard_ad", [{base, Base}, |
126 |
|
|
{filter, Filter}, |
127 |
|
|
{attributes, []}]) of |
128 |
|
|
#eldap_search_result{entries = [E | _]} -> |
129 |
|
|
E; |
130 |
|
|
_ -> |
131 |
|
|
false |
132 |
|
|
end. |
133 |
|
|
|
134 |
|
|
is_attribute_read_allowed(Name,From,To) -> |
135 |
|
|
true. |
136 |
|
|
|
137 |
|
|
ldap_attribute_to_vcard(Prefix,{Name,Values},From,To) -> |
138 |
|
|
case is_attribute_read_allowed(Name,From,To) of |
139 |
|
|
true -> |
140 |
|
|
ldap_lca_to_vcard(Prefix,stringprep:tolower(Name),Values); |
141 |
|
|
_ -> |
142 |
|
|
none |
143 |
|
|
end. |
144 |
|
|
|
145 |
|
|
ldap_lca_to_vcard(vCard,"displayname",[Value|_]) -> |
146 |
|
|
{xmlelement,"FN",[],[{xmlcdata,Value}]}; |
147 |
|
|
|
148 |
|
|
ldap_lca_to_vcard(vCard,"cn",[Value|_]) -> |
149 |
|
|
{xmlelement,"NICKNAME",[],[{xmlcdata,Value}]}; |
150 |
|
|
|
151 |
|
|
ldap_lca_to_vcard(vCard,"title",[Value|_]) -> |
152 |
|
|
{xmlelement,"TITLE",[],[{xmlcdata,Value}]}; |
153 |
|
|
|
154 |
|
|
ldap_lca_to_vcard(vCard,"wwwhomepage",[Value|_]) -> |
155 |
|
|
{xmlelement,"URL",[],[{xmlcdata,Value}]}; |
156 |
|
|
|
157 |
|
|
ldap_lca_to_vcard(vCard,"description",[Value|_]) -> |
158 |
|
|
{xmlelement,"DESC",[],[{xmlcdata,Value}]}; |
159 |
|
|
|
160 |
|
|
ldap_lca_to_vcard(vCard,"telephonenumber",[Value|_]) -> |
161 |
|
|
{xmlelement,"TEL",[],[{xmlelement,"VOICE",[],[]}, |
162 |
|
|
{xmlelement,"WORK",[],[]}, |
163 |
|
|
{xmlelement,"NUMBER",[],[{xmlcdata,Value}]}]}; |
164 |
|
|
|
165 |
|
|
ldap_lca_to_vcard(vCard,"mail",[Value|_]) -> |
166 |
|
|
{xmlelement,"EMAIL",[],[{xmlelement,"INTERNET",[],[]}, |
167 |
|
|
{xmlelement,"PREF",[],[]}, |
168 |
|
|
{xmlelement,"USERID",[],[{xmlcdata,Value}]}]}; |
169 |
|
|
|
170 |
|
|
ldap_lca_to_vcard(vCardN,"sn",[Value|_]) -> |
171 |
|
|
{xmlelement,"FAMILY",[],[{xmlcdata,Value}]}; |
172 |
|
|
|
173 |
|
|
ldap_lca_to_vcard(vCardN,"givenname",[Value|_]) -> |
174 |
|
|
{xmlelement,"GIVEN",[],[{xmlcdata,Value}]}; |
175 |
|
|
|
176 |
|
|
ldap_lca_to_vcard(vCardN,"initials",[Value|_]) -> |
177 |
|
|
{xmlelement,"MIDDLE",[],[{xmlcdata,Value}]}; |
178 |
|
|
|
179 |
|
|
ldap_lca_to_vcard(vCardAdr,"streetaddress",[Value|_]) -> |
180 |
|
|
{xmlelement,"STREET",[],[{xmlcdata,Value}]}; |
181 |
|
|
ldap_lca_to_vcard(vCardAdr,"co",[Value|_]) -> |
182 |
|
|
{xmlelement,"CTRY",[],[{xmlcdata,Value}]}; |
183 |
|
|
ldap_lca_to_vcard(vCardAdr,"l",[Value|_]) -> |
184 |
|
|
{xmlelement,"LOCALITY",[],[{xmlcdata,Value}]}; |
185 |
|
|
ldap_lca_to_vcard(vCardAdr,"st",[Value|_]) -> |
186 |
|
|
{xmlelement,"REGION",[],[{xmlcdata,Value}]}; |
187 |
|
|
ldap_lca_to_vcard(vCardAdr,"postalcode",[Value|_]) -> |
188 |
|
|
{xmlelement,"PCODE",[],[{xmlcdata,Value}]}; |
189 |
|
|
ldap_lca_to_vcard(vCardO,"company",[Value|_]) -> |
190 |
|
|
{xmlelement,"ORGNAME",[],[{xmlcdata,Value}]}; |
191 |
|
|
|
192 |
|
|
ldap_lca_to_vcard(vCardO,"department",[Value|_]) -> |
193 |
|
|
{xmlelement,"ORGUNIT",[],[{xmlcdata,Value}]}; |
194 |
|
|
|
195 |
|
|
ldap_lca_to_vcard(_,_,_) -> none. |
196 |
|
|
|
197 |
|
|
ldap_attributes_to_vcard(Attributes,From,To) -> |
198 |
|
|
Elts = lists:map(fun(Attr) -> |
199 |
|
|
ldap_attribute_to_vcard(vCard,Attr,From,To) |
200 |
|
|
end,Attributes), |
201 |
|
|
FElts = [ X || X <- Elts, X /= none ], |
202 |
|
|
NElts = lists:map(fun(Attr) -> |
203 |
|
|
ldap_attribute_to_vcard(vCardN,Attr,From,To) |
204 |
|
|
end,Attributes), |
205 |
|
|
FNElts = [ X || X <- NElts, X /= none ], |
206 |
|
|
|
207 |
|
|
ADRElts = lists:map(fun(Attr) -> |
208 |
|
|
ldap_attribute_to_vcard(vCardAdr,Attr,From,To) |
209 |
|
|
end,Attributes), |
210 |
|
|
FADRElts = [ X || X <- ADRElts, X /= none ], |
211 |
|
|
|
212 |
|
|
OElts = lists:map(fun(Attr) -> |
213 |
|
|
ldap_attribute_to_vcard(vCardO,Attr,From,To) |
214 |
|
|
end,Attributes), |
215 |
|
|
FOElts = [ X || X <- OElts, X /= none ], |
216 |
|
|
[{xmlelement, "vCard", [{"xmlns", ?NS_VCARD}], |
217 |
|
|
lists:append(FElts, |
218 |
|
|
[{xmlelement,"N",[],FNElts}, |
219 |
|
|
{xmlelement,"ADR",[],FADRElts}, |
220 |
|
|
{xmlelement,"ORG",[],FOElts}]) |
221 |
|
|
}]. |
222 |
|
|
|
223 |
|
|
process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) -> |
224 |
|
|
case Type of |
225 |
|
|
set -> |
226 |
|
|
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}; |
227 |
|
|
get -> |
228 |
|
|
#jid{luser = LUser, lserver = LServer} = To, |
229 |
|
|
case find_ldap_user(LServer, LUser) of |
230 |
|
|
#eldap_entry{attributes = Attributes} -> |
231 |
|
|
Vcard = ldap_attributes_to_vcard(Attributes,From,To), |
232 |
|
|
IQ#iq{type = result, sub_el = Vcard}; |
233 |
|
|
_ -> |
234 |
|
|
IQ#iq{type = result, sub_el = []} |
235 |
|
|
end |
236 |
|
|
end. |
237 |
|
|
|
238 |
|
|
-define(TLFIELD(Type, Label, Var), |
239 |
|
|
{xmlelement, "field", [{"type", Type}, |
240 |
|
|
{"label", translate:translate(Lang, Label)}, |
241 |
|
|
{"var", Var}], []}). |
242 |
|
|
|
243 |
|
|
|
244 |
|
|
-define(FORM(JID), |
245 |
|
|
[{xmlelement, "instructions", [], |
246 |
|
|
[{xmlcdata, translate:translate(Lang, "You need an x:data capable client to search")}]}, |
247 |
|
|
{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}], |
248 |
|
|
[{xmlelement, "title", [], |
249 |
|
|
[{xmlcdata, translate:translate(Lang, "Search users in ") ++ |
250 |
|
|
jlib:jid_to_string(JID)}]}, |
251 |
|
|
{xmlelement, "instructions", [], |
252 |
|
|
[{xmlcdata, translate:translate(Lang, "Fill in fields to search " |
253 |
|
|
"for any matching Jabber User")}]}, |
254 |
|
|
?TLFIELD("text-single", "User", "user"), |
255 |
|
|
?TLFIELD("text-single", "Full Name", "fn"), |
256 |
|
|
?TLFIELD("text-single", "Given Name", "given"), |
257 |
|
|
?TLFIELD("text-single", "Middle Name", "middle"), |
258 |
|
|
?TLFIELD("text-single", "Family Name", "family"), |
259 |
|
|
?TLFIELD("text-single", "Nickname", "nickname"), |
260 |
|
|
?TLFIELD("text-single", "Birthday", "bday"), |
261 |
|
|
?TLFIELD("text-single", "Country", "ctry"), |
262 |
|
|
?TLFIELD("text-single", "City", "locality"), |
263 |
|
|
?TLFIELD("text-single", "email", "email"), |
264 |
|
|
?TLFIELD("text-single", "Organization Name", "orgname"), |
265 |
|
|
?TLFIELD("text-single", "Organization Unit", "orgunit") |
266 |
|
|
]}]). |
267 |
|
|
|
268 |
|
|
|
269 |
|
|
|
270 |
|
|
|
271 |
|
|
do_route(ServerHost, From, To, Packet) -> |
272 |
|
|
#jid{user = User, resource = Resource} = To, |
273 |
|
|
if |
274 |
|
|
(User /= "") or (Resource /= "") -> |
275 |
|
|
Err = jlib:make_error_reply(Packet, ?ERR_SERVICE_UNAVAILABLE), |
276 |
|
|
ejabberd_router ! {route, To, From, Err}; |
277 |
|
|
true -> |
278 |
|
|
IQ = jlib:iq_query_info(Packet), |
279 |
|
|
case IQ of |
280 |
|
|
#iq{type = Type, xmlns = ?NS_SEARCH, lang = Lang, sub_el = SubEl} -> |
281 |
|
|
case Type of |
282 |
|
|
set -> |
283 |
|
|
XDataEl = find_xdata_el(SubEl), |
284 |
|
|
case XDataEl of |
285 |
|
|
false -> |
286 |
|
|
Err = jlib:make_error_reply( |
287 |
|
|
Packet, ?ERR_BAD_REQUEST), |
288 |
|
|
ejabberd_router:route(To, From, Err); |
289 |
|
|
_ -> |
290 |
|
|
XData = jlib:parse_xdata_submit(XDataEl), |
291 |
|
|
case XData of |
292 |
|
|
invalid -> |
293 |
|
|
Err = jlib:make_error_reply( |
294 |
|
|
Packet, |
295 |
|
|
?ERR_BAD_REQUEST), |
296 |
|
|
ejabberd_router:route(To, From, |
297 |
|
|
Err); |
298 |
|
|
_ -> |
299 |
|
|
ResIQ = |
300 |
|
|
IQ#iq{ |
301 |
|
|
type = result, |
302 |
|
|
sub_el = |
303 |
|
|
[{xmlelement, |
304 |
|
|
"query", |
305 |
|
|
[{"xmlns", ?NS_SEARCH}], |
306 |
|
|
[{xmlelement, "x", |
307 |
|
|
[{"xmlns", ?NS_XDATA}, |
308 |
|
|
{"type", "result"}], |
309 |
|
|
search_result(Lang, To, ServerHost, XData) |
310 |
|
|
}]}]}, |
311 |
|
|
ejabberd_router:route( |
312 |
|
|
To, From, jlib:iq_to_xml(ResIQ)) |
313 |
|
|
end |
314 |
|
|
end; |
315 |
|
|
get -> |
316 |
|
|
ResIQ = IQ#iq{type = result, |
317 |
|
|
sub_el = [{xmlelement, |
318 |
|
|
"query", |
319 |
|
|
[{"xmlns", ?NS_SEARCH}], |
320 |
|
|
?FORM(To) |
321 |
|
|
}]}, |
322 |
|
|
ejabberd_router:route(To, |
323 |
|
|
From, |
324 |
|
|
jlib:iq_to_xml(ResIQ)) |
325 |
|
|
end; |
326 |
|
|
#iq{type = Type, xmlns = ?NS_DISCO_INFO, sub_el = SubEl} -> |
327 |
|
|
case Type of |
328 |
|
|
set -> |
329 |
|
|
Err = jlib:make_error_reply( |
330 |
|
|
Packet, ?ERR_NOT_ALLOWED), |
331 |
|
|
ejabberd_router:route(To, From, Err); |
332 |
|
|
get -> |
333 |
|
|
ResIQ = |
334 |
|
|
IQ#iq{type = result, |
335 |
|
|
sub_el = [{xmlelement, |
336 |
|
|
"query", |
337 |
|
|
[{"xmlns", ?NS_DISCO_INFO}], |
338 |
|
|
[{xmlelement, "identity", |
339 |
|
|
[{"category", "directory"}, |
340 |
|
|
{"type", "user"}, |
341 |
|
|
{"name", |
342 |
|
|
"vCard User Search"}], |
343 |
|
|
[]}, |
344 |
|
|
{xmlelement, "feature", |
345 |
|
|
[{"var", ?NS_SEARCH}], []}, |
346 |
|
|
{xmlelement, "feature", |
347 |
|
|
[{"var", ?NS_VCARD}], []} |
348 |
|
|
] |
349 |
|
|
}]}, |
350 |
|
|
ejabberd_router:route(To, |
351 |
|
|
From, |
352 |
|
|
jlib:iq_to_xml(ResIQ)) |
353 |
|
|
end; |
354 |
|
|
#iq{type = Type, xmlns = ?NS_DISCO_ITEMS, sub_el = SubEl} -> |
355 |
|
|
case Type of |
356 |
|
|
set -> |
357 |
|
|
Err = jlib:make_error_reply( |
358 |
|
|
Packet, ?ERR_NOT_ALLOWED), |
359 |
|
|
ejabberd_router:route(To, From, Err); |
360 |
|
|
get -> |
361 |
|
|
ResIQ = |
362 |
|
|
IQ#iq{type = result, |
363 |
|
|
sub_el = [{xmlelement, |
364 |
|
|
"query", |
365 |
|
|
[{"xmlns", ?NS_DISCO_ITEMS}], |
366 |
|
|
[]}]}, |
367 |
|
|
ejabberd_router:route(To, |
368 |
|
|
From, |
369 |
|
|
jlib:iq_to_xml(ResIQ)) |
370 |
|
|
end; |
371 |
|
|
#iq{type = get, xmlns = ?NS_VCARD, lang = Lang} -> |
372 |
|
|
ResIQ = |
373 |
|
|
IQ#iq{type = result, |
374 |
|
|
sub_el = [{xmlelement, |
375 |
|
|
"vCard", |
376 |
|
|
[{"xmlns", ?NS_VCARD}], |
377 |
|
|
iq_get_vcard(Lang)}]}, |
378 |
|
|
ejabberd_router:route(To, |
379 |
|
|
From, |
380 |
|
|
jlib:iq_to_xml(ResIQ)); |
381 |
|
|
_ -> |
382 |
|
|
Err = jlib:make_error_reply(Packet, |
383 |
|
|
?ERR_SERVICE_UNAVAILABLE), |
384 |
|
|
ejabberd_router:route(To, From, Err) |
385 |
|
|
end |
386 |
|
|
end. |
387 |
|
|
|
388 |
|
|
iq_get_vcard(Lang) -> |
389 |
|
|
[{xmlelement, "FN", [], |
390 |
|
|
[{xmlcdata, "ejabberd/mod_vcard"}]}, |
391 |
|
|
{xmlelement, "URL", [], |
392 |
|
|
[{xmlcdata, |
393 |
|
|
"http://ejabberd.jabberstudio.org/"}]}, |
394 |
|
|
{xmlelement, "DESC", [], |
395 |
|
|
[{xmlcdata, translate:translate( |
396 |
|
|
Lang, |
397 |
|
|
"ejabberd vCard module\n" |
398 |
|
|
"Copyright (c) 2003-2005 Alexey Shchepin")}]}]. |
399 |
|
|
|
400 |
|
|
find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) -> |
401 |
|
|
find_xdata_el1(SubEls). |
402 |
|
|
|
403 |
|
|
find_xdata_el1([]) -> |
404 |
|
|
false; |
405 |
|
|
find_xdata_el1([{xmlelement, Name, Attrs, SubEls} | Els]) -> |
406 |
|
|
case xml:get_attr_s("xmlns", Attrs) of |
407 |
|
|
?NS_XDATA -> |
408 |
|
|
{xmlelement, Name, Attrs, SubEls}; |
409 |
|
|
_ -> |
410 |
|
|
find_xdata_el1(Els) |
411 |
|
|
end; |
412 |
|
|
find_xdata_el1([_ | Els]) -> |
413 |
|
|
find_xdata_el1(Els). |
414 |
|
|
|
415 |
|
|
-define(LFIELD(Label, Var), |
416 |
|
|
{xmlelement, "field", [{"label", translate:translate(Lang, Label)}, |
417 |
|
|
{"var", Var}], []}). |
418 |
|
|
|
419 |
|
|
search_result(Lang, JID, ServerHost, Data) -> |
420 |
|
|
[{xmlelement, "title", [], |
421 |
|
|
[{xmlcdata, translate:translate(Lang, "Results of search in ") ++ |
422 |
|
|
jlib:jid_to_string(JID)}]}, |
423 |
|
|
{xmlelement, "reported", [], |
424 |
|
|
[?LFIELD("JID", "jid"), |
425 |
|
|
?LFIELD("Full Name", "fn"), |
426 |
|
|
?LFIELD("Given Name", "given"), |
427 |
|
|
?LFIELD("Middle Name", "middle"), |
428 |
|
|
?LFIELD("Family Name", "family"), |
429 |
|
|
?LFIELD("Nickname", "nickname"), |
430 |
|
|
?LFIELD("Birthday", "bday"), |
431 |
|
|
?LFIELD("Country", "ctry"), |
432 |
|
|
?LFIELD("City", "locality"), |
433 |
|
|
?LFIELD("email", "email"), |
434 |
|
|
?LFIELD("Organization Name", "orgname"), |
435 |
|
|
?LFIELD("Organization Unit", "orgunit") |
436 |
|
|
]}] ++ lists:map(fun(E) -> |
437 |
|
|
record_to_item(E#eldap_entry.attributes) |
438 |
|
|
end, search(ServerHost, Data)). |
439 |
|
|
|
440 |
|
|
-define(FIELD(Var, Val), |
441 |
|
|
{xmlelement, "field", [{"var", Var}], |
442 |
|
|
[{xmlelement, "value", [], |
443 |
|
|
[{xmlcdata, Val}]}]}). |
444 |
|
|
|
445 |
|
|
case_exact_compare(none,_) -> |
446 |
|
|
false; |
447 |
|
|
case_exact_compare(_,none) -> |
448 |
|
|
false; |
449 |
|
|
case_exact_compare(X,Y) -> |
450 |
|
|
X > Y. |
451 |
|
|
|
452 |
|
|
ldap_sort_entries(L) -> |
453 |
|
|
lists:sort(fun(E1,E2) -> |
454 |
|
|
case_exact_compare(ldap_get_value(E1,"cn"),ldap_get_value(E2,"cn")) |
455 |
|
|
end,L). |
456 |
|
|
|
457 |
|
|
ldap_get_value(E,Attribute) -> |
458 |
|
|
#eldap_entry{attributes = Attributes} = E, |
459 |
|
|
case lists:filter(fun({A,_}) -> |
460 |
|
|
string:equal(A,Attribute) |
461 |
|
|
end,Attributes) of |
462 |
|
|
[{Attr,[Value|_]}] -> |
463 |
|
|
Value; |
464 |
|
|
_ -> |
465 |
|
|
none |
466 |
|
|
end. |
467 |
|
|
|
468 |
|
|
ldap_attribute_to_item("samaccountname",Value) -> |
469 |
|
|
[ |
470 |
|
|
?FIELD("jid",Value ++ "@" ++ ?MYNAME), |
471 |
|
|
?FIELD("uid",Value) |
472 |
|
|
]; |
473 |
|
|
|
474 |
|
|
ldap_attribute_to_item("cn",Value) -> |
475 |
|
|
[ |
476 |
|
|
?FIELD("nickname",Value) |
477 |
|
|
]; |
478 |
|
|
|
479 |
|
|
ldap_attribute_to_item("displayname",Value) -> |
480 |
|
|
[ |
481 |
|
|
?FIELD("fn",Value) |
482 |
|
|
]; |
483 |
|
|
|
484 |
|
|
ldap_attribute_to_item("sn",Value) -> |
485 |
|
|
[ |
486 |
|
|
?FIELD("family",Value) |
487 |
|
|
]; |
488 |
|
|
ldap_attribute_to_item("co",Value) -> |
489 |
|
|
[ |
490 |
|
|
?FIELD("ctry",Value) |
491 |
|
|
]; |
492 |
|
|
ldap_attribute_to_item("l",Value) -> |
493 |
|
|
[ |
494 |
|
|
?FIELD("locality",Value) |
495 |
|
|
]; |
496 |
|
|
|
497 |
|
|
ldap_attribute_to_item("givenname",Value) -> |
498 |
|
|
[ |
499 |
|
|
?FIELD("given",Value) |
500 |
|
|
]; |
501 |
|
|
|
502 |
|
|
ldap_attribute_to_item("initials",Value) -> |
503 |
|
|
[ |
504 |
|
|
?FIELD("middle",Value) |
505 |
|
|
]; |
506 |
|
|
|
507 |
|
|
ldap_attribute_to_item("mail",Value) -> |
508 |
|
|
[ |
509 |
|
|
?FIELD("email",Value) |
510 |
|
|
]; |
511 |
|
|
|
512 |
|
|
ldap_attribute_to_item("company",Value) -> |
513 |
|
|
[ |
514 |
|
|
?FIELD("orgname",Value) |
515 |
|
|
]; |
516 |
|
|
|
517 |
|
|
ldap_attribute_to_item("department",Value) -> |
518 |
|
|
[ |
519 |
|
|
?FIELD("orgunit",Value) |
520 |
|
|
]; |
521 |
|
|
|
522 |
|
|
ldap_attribute_to_item(_,_) -> |
523 |
|
|
[none]. |
524 |
|
|
|
525 |
|
|
record_to_item(Attributes) -> |
526 |
|
|
List = lists:append(lists:map(fun({Attr,[Value|_]}) -> |
527 |
|
|
ldap_attribute_to_item(stringprep:tolower(Attr),Value) |
528 |
|
|
end,Attributes)), |
529 |
|
|
FList = [X || X <- List, X /= none], |
530 |
|
|
{xmlelement, "item", [],FList}. |
531 |
|
|
|
532 |
|
|
search(LServer, Data) -> |
533 |
|
|
% AdGroup = ejabberd_config:get_local_option({ad_group, LServer}), |
534 |
|
|
FilterDef = make_filter(Data), |
535 |
|
|
FilterPerson = eldap:equalityMatch("objectCategory", "person"), |
536 |
|
|
FilterComp = eldap:equalityMatch("objectClass", "computer"), |
537 |
|
|
FilterHidden = eldap:equalityMatch("description", "hidden"), |
538 |
|
|
% FilterGroup = eldap:equalityMatch("memberOf", AdGroup), |
539 |
|
|
FilterLive = eldap:equalityMatch("userAccountControl", "66050"), |
540 |
|
|
Filter = eldap:'and'([ |
541 |
|
|
FilterDef, |
542 |
|
|
FilterPerson, |
543 |
|
|
% FilterGroup, |
544 |
|
|
eldap:'not'(FilterComp), |
545 |
|
|
eldap:'not'(FilterHidden), |
546 |
|
|
eldap:'not'(FilterLive)]), |
547 |
|
|
Base = ejabberd_config:get_local_option({ad_base, LServer}), |
548 |
|
|
UIDAttr = ejabberd_config:get_local_option({ad_uidattr, LServer}), |
549 |
|
|
case eldap:search("mod_vcard_ad",[{base, Base}, |
550 |
|
|
{filter, Filter}, |
551 |
|
|
{attributes, []}]) of |
552 |
|
|
#eldap_search_result{entries = E} -> |
553 |
|
|
[X || X <- E, |
554 |
|
|
ejabberd_auth:is_user_exists( |
555 |
|
|
ldap_get_value(X, UIDAttr), LServer)]; |
556 |
|
|
Err -> |
557 |
|
|
?ERROR_MSG("Bad search: ~p", [[LServer, {base, Base}, |
558 |
|
|
{filter, Filter}, |
559 |
|
|
{attributes, []}]]) |
560 |
|
|
end. |
561 |
|
|
|
562 |
|
|
|
563 |
|
|
make_filter(Data) -> |
564 |
|
|
Filter = [X || X <- lists:map(fun(R) -> |
565 |
|
|
make_assertion(R) |
566 |
|
|
end, Data), |
567 |
|
|
X /= none ], |
568 |
|
|
case Filter of |
569 |
|
|
[F] -> |
570 |
|
|
F; |
571 |
|
|
_ -> |
572 |
|
|
eldap:'and'(Filter) |
573 |
|
|
end. |
574 |
|
|
|
575 |
|
|
|
576 |
|
|
make_assertion("givenName",Value) -> |
577 |
|
|
eldap:substrings("givenName",[{any,Value}]); |
578 |
|
|
|
579 |
|
|
make_assertion("cn",Value) -> |
580 |
|
|
eldap:substrings("cn",[{any,Value}]); |
581 |
|
|
|
582 |
|
|
make_assertion("sn",Value) -> |
583 |
|
|
eldap:substrings("sn",[{any,Value}]); |
584 |
|
|
|
585 |
|
|
make_assertion(Attr, Value) -> |
586 |
|
|
eldap:equalityMatch(Attr,Value). |
587 |
|
|
|
588 |
|
|
make_assertion({SVar, [Val]}) -> |
589 |
|
|
LAttr = ldap_attribute(SVar), |
590 |
|
|
case LAttr of |
591 |
|
|
none -> |
592 |
|
|
none; |
593 |
|
|
_ -> |
594 |
|
|
if |
595 |
|
|
is_list(Val) and (Val /= "") -> |
596 |
|
|
make_assertion(LAttr,Val); |
597 |
|
|
true -> |
598 |
|
|
none |
599 |
|
|
end |
600 |
|
|
end. |
601 |
|
|
|
602 |
|
|
ldap_attribute("user") -> |
603 |
|
|
"samaccountname"; |
604 |
|
|
|
605 |
|
|
ldap_attribute("fn") -> |
606 |
|
|
"cn"; |
607 |
|
|
|
608 |
|
|
ldap_attribute("family") -> |
609 |
|
|
"sn"; |
610 |
|
|
|
611 |
|
|
ldap_attribute("given") -> |
612 |
|
|
"givenName"; |
613 |
|
|
|
614 |
|
|
ldap_attribute("middle") -> |
615 |
|
|
"initials"; |
616 |
|
|
|
617 |
|
|
ldap_attribute("email") -> |
618 |
|
|
"mail"; |
619 |
|
|
|
620 |
|
|
ldap_attribute("orgname") -> |
621 |
|
|
"company"; |
622 |
|
|
|
623 |
|
|
ldap_attribute("orgunit") -> |
624 |
|
|
"department"; |
625 |
|
|
|
626 |
|
|
ldap_attribute(_) -> |
627 |
|
|
none. |
628 |
|
|
|
629 |
|
|
remove_user(User) -> |
630 |
|
|
true. |
631 |
|
|
|