/[smecontribs]/rpms/ejabberd/contribs7/mod_vcard_ad.erl
ViewVC logotype

Annotation of /rpms/ejabberd/contribs7/mod_vcard_ad.erl

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.3 - (hide annotations) (download)
Tue Nov 25 16:20:11 2008 UTC (15 years, 5 months ago) by slords
Branch: MAIN
CVS Tags: ejabberd-2_0_5-2_el4_sme, HEAD
Changes since 1.2: +0 -0 lines
Restore

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    

admin@koozali.org
ViewVC Help
Powered by ViewVC 1.2.1 RSS 2.0 feed