aboutsummaryrefslogtreecommitdiff
path: root/src/mod_vcard_ldap.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_vcard_ldap.erl')
-rw-r--r--src/mod_vcard_ldap.erl1317
1 files changed, 662 insertions, 655 deletions
diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl
index d3e60774a..be9bc7c53 100644
--- a/src/mod_vcard_ldap.erl
+++ b/src/mod_vcard_ldap.erl
@@ -25,125 +25,108 @@
%%%----------------------------------------------------------------------
-module(mod_vcard_ldap).
+
-author('alexey@process-one.net').
-behaviour(gen_server).
+
-behaviour(gen_mod).
%% gen_server callbacks.
--export([init/1,
- handle_info/2,
- handle_call/3,
- handle_cast/2,
- terminate/2,
- code_change/3
- ]).
-
--export([start/2,
- start_link/2,
- stop/1,
- get_sm_features/5,
- process_local_iq/3,
- process_sm_iq/3,
- remove_user/1,
- route/4
- ]).
+-export([init/1, handle_info/2, handle_call/3,
+ handle_cast/2, terminate/2, code_change/3]).
+
+-export([start/2, start_link/2, stop/1,
+ get_sm_features/5, process_local_iq/3, process_sm_iq/3,
+ remove_user/1, route/4]).
-include("ejabberd.hrl").
+
-include("eldap/eldap.hrl").
+
-include("jlib.hrl").
-define(PROCNAME, ejabberd_mod_vcard_ldap).
--record(state, {serverhost,
- myhost,
- eldap_id,
- search,
- servers,
- backups,
- port,
- tls_options,
- dn,
- base,
- password,
- uids,
- vcard_map,
- vcard_map_attrs,
- user_filter,
- search_filter,
- search_fields,
- search_reported,
- search_reported_attrs,
- deref_aliases,
- matches
- }).
+-record(state,
+ {serverhost = <<"">> :: binary(),
+ myhost = <<"">> :: binary(),
+ eldap_id = <<"">> :: binary(),
+ search = true :: boolean(),
+ servers = [] :: [binary()],
+ backups = [] :: [binary()],
+ port = ?LDAP_PORT :: inet:port_number(),
+ tls_options = [] :: list(),
+ dn = <<"">> :: binary(),
+ base = <<"">> :: binary(),
+ password = <<"">> :: binary(),
+ uids = [] :: [{binary()} | {binary(), binary()}],
+ vcard_map = [] :: [{binary(), binary(), [binary()]}],
+ vcard_map_attrs = [] :: [binary()],
+ user_filter = <<"">> :: binary(),
+ search_filter :: eldap:filter(),
+ search_fields = [] :: [{binary(), binary()}],
+ search_reported = [] :: [{binary(), binary()}],
+ search_reported_attrs = [] :: [binary()],
+ deref_aliases = never :: never | searching | finding | always,
+ matches = 0 :: non_neg_integer()}).
-define(VCARD_MAP,
- [{"NICKNAME", "%u", []},
- {"FN", "%s", ["displayName"]},
- {"FAMILY", "%s", ["sn"]},
- {"GIVEN", "%s", ["givenName"]},
- {"MIDDLE", "%s", ["initials"]},
- {"ORGNAME", "%s", ["o"]},
- {"ORGUNIT", "%s", ["ou"]},
- {"CTRY", "%s", ["c"]},
- {"LOCALITY", "%s", ["l"]},
- {"STREET", "%s", ["street"]},
- {"REGION", "%s", ["st"]},
- {"PCODE", "%s", ["postalCode"]},
- {"TITLE", "%s", ["title"]},
- {"URL", "%s", ["labeleduri"]},
- {"DESC", "%s", ["description"]},
- {"TEL", "%s", ["telephoneNumber"]},
- {"EMAIL", "%s", ["mail"]},
- {"BDAY", "%s", ["birthDay"]},
- {"ROLE", "%s", ["employeeType"]},
- {"PHOTO", "%s", ["jpegPhoto"]}
- ]).
+ [{<<"NICKNAME">>, <<"%u">>, []},
+ {<<"FN">>, <<"%s">>, [<<"displayName">>]},
+ {<<"FAMILY">>, <<"%s">>, [<<"sn">>]},
+ {<<"GIVEN">>, <<"%s">>, [<<"givenName">>]},
+ {<<"MIDDLE">>, <<"%s">>, [<<"initials">>]},
+ {<<"ORGNAME">>, <<"%s">>, [<<"o">>]},
+ {<<"ORGUNIT">>, <<"%s">>, [<<"ou">>]},
+ {<<"CTRY">>, <<"%s">>, [<<"c">>]},
+ {<<"LOCALITY">>, <<"%s">>, [<<"l">>]},
+ {<<"STREET">>, <<"%s">>, [<<"street">>]},
+ {<<"REGION">>, <<"%s">>, [<<"st">>]},
+ {<<"PCODE">>, <<"%s">>, [<<"postalCode">>]},
+ {<<"TITLE">>, <<"%s">>, [<<"title">>]},
+ {<<"URL">>, <<"%s">>, [<<"labeleduri">>]},
+ {<<"DESC">>, <<"%s">>, [<<"description">>]},
+ {<<"TEL">>, <<"%s">>, [<<"telephoneNumber">>]},
+ {<<"EMAIL">>, <<"%s">>, [<<"mail">>]},
+ {<<"BDAY">>, <<"%s">>, [<<"birthDay">>]},
+ {<<"ROLE">>, <<"%s">>, [<<"employeeType">>]},
+ {<<"PHOTO">>, <<"%s">>, [<<"jpegPhoto">>]}]).
-define(SEARCH_FIELDS,
- [{"User", "%u"},
- {"Full Name", "displayName"},
- {"Given Name", "givenName"},
- {"Middle Name", "initials"},
- {"Family Name", "sn"},
- {"Nickname", "%u"},
- {"Birthday", "birthDay"},
- {"Country", "c"},
- {"City", "l"},
- {"Email", "mail"},
- {"Organization Name", "o"},
- {"Organization Unit", "ou"}
- ]).
+ [{<<"User">>, <<"%u">>},
+ {<<"Full Name">>, <<"displayName">>},
+ {<<"Given Name">>, <<"givenName">>},
+ {<<"Middle Name">>, <<"initials">>},
+ {<<"Family Name">>, <<"sn">>},
+ {<<"Nickname">>, <<"%u">>},
+ {<<"Birthday">>, <<"birthDay">>},
+ {<<"Country">>, <<"c">>}, {<<"City">>, <<"l">>},
+ {<<"Email">>, <<"mail">>},
+ {<<"Organization Name">>, <<"o">>},
+ {<<"Organization Unit">>, <<"ou">>}]).
-define(SEARCH_REPORTED,
- [{"Full Name", "FN"},
- {"Given Name", "FIRST"},
- {"Middle Name", "MIDDLE"},
- {"Family Name", "LAST"},
- {"Nickname", "NICK"},
- {"Birthday", "BDAY"},
- {"Country", "CTRY"},
- {"City", "LOCALITY"},
- {"Email", "EMAIL"},
- {"Organization Name", "ORGNAME"},
- {"Organization Unit", "ORGUNIT"}
- ]).
-
-%% Unused callbacks.
-handle_cast(_Request, State) ->
- {noreply, State}.
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-%% -----
-
+ [{<<"Full Name">>, <<"FN">>},
+ {<<"Given Name">>, <<"FIRST">>},
+ {<<"Middle Name">>, <<"MIDDLE">>},
+ {<<"Family Name">>, <<"LAST">>},
+ {<<"Nickname">>, <<"NICK">>},
+ {<<"Birthday">>, <<"BDAY">>},
+ {<<"Country">>, <<"CTRY">>},
+ {<<"City">>, <<"LOCALITY">>},
+ {<<"Email">>, <<"EMAIL">>},
+ {<<"Organization Name">>, <<"ORGNAME">>},
+ {<<"Organization Unit">>, <<"ORGUNIT">>}]).
+
+handle_cast(_Request, State) -> {noreply, State}.
+
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
start(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
- ChildSpec = {
- Proc, {?MODULE, start_link, [Host, Opts]},
- transient, 1000, worker, [?MODULE]
- },
+ ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]},
+ transient, 1000, worker, [?MODULE]},
supervisor:start_child(ejabberd_sup, ChildSpec).
stop(Host) ->
@@ -154,125 +137,126 @@ stop(Host) ->
terminate(_Reason, State) ->
Host = State#state.serverhost,
- gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD),
- gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD),
- ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
+ gen_iq_handler:remove_iq_handler(ejabberd_local, Host,
+ ?NS_VCARD),
+ gen_iq_handler:remove_iq_handler(ejabberd_sm, Host,
+ ?NS_VCARD),
+ ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE,
+ get_sm_features, 50),
case State#state.search of
- true ->
- ejabberd_router:unregister_route(State#state.myhost);
- _ ->
- ok
+ true ->
+ ejabberd_router:unregister_route(State#state.myhost);
+ _ -> ok
end.
start_link(Host, Opts) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
- gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
+ gen_server:start_link({local, Proc}, ?MODULE,
+ [Host, Opts], []).
init([Host, Opts]) ->
State = parse_options(Host, Opts),
- IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
- gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD,
- ?MODULE, process_local_iq, IQDisc),
- gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD,
- ?MODULE, process_sm_iq, IQDisc),
- ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
+ IQDisc = gen_mod:get_opt(iqdisc, Opts, fun gen_iq_handler:check_type/1,
+ one_queue),
+ gen_iq_handler:add_iq_handler(ejabberd_local, Host,
+ ?NS_VCARD, ?MODULE, process_local_iq, IQDisc),
+ gen_iq_handler:add_iq_handler(ejabberd_sm, Host,
+ ?NS_VCARD, ?MODULE, process_sm_iq, IQDisc),
+ ejabberd_hooks:add(disco_sm_features, Host, ?MODULE,
+ get_sm_features, 50),
eldap_pool:start_link(State#state.eldap_id,
- State#state.servers,
- State#state.backups,
- State#state.port,
- State#state.dn,
- State#state.password,
- State#state.tls_options),
+ State#state.servers, State#state.backups,
+ State#state.port, State#state.dn,
+ State#state.password, State#state.tls_options),
case State#state.search of
- true ->
- ejabberd_router:register_route(State#state.myhost);
- _ ->
- ok
+ true ->
+ ejabberd_router:register_route(State#state.myhost);
+ _ -> ok
end,
{ok, State}.
handle_info({route, From, To, Packet}, State) ->
case catch do_route(State, From, To, Packet) of
- Pid when is_pid(Pid) ->
- ok;
- _ ->
- Err = jlib:make_error_reply(Packet, ?ERR_INTERNAL_SERVER_ERROR),
- ejabberd_router:route(To, From, Err)
+ Pid when is_pid(Pid) -> ok;
+ _ ->
+ Err = jlib:make_error_reply(Packet,
+ ?ERR_INTERNAL_SERVER_ERROR),
+ ejabberd_router:route(To, From, Err)
end,
{noreply, State};
+handle_info(_Info, State) -> {noreply, State}.
-handle_info(_Info, State) ->
- {noreply, State}.
-
-get_sm_features({error, _Error} = Acc, _From, _To, _Node, _Lang) ->
+get_sm_features({error, _Error} = Acc, _From, _To,
+ _Node, _Lang) ->
Acc;
get_sm_features(Acc, _From, _To, Node, _Lang) ->
case Node of
- [] ->
- case Acc of
- {result, Features} ->
- {result, [?NS_VCARD | Features]};
- empty ->
- {result, [?NS_VCARD]}
- end;
- _ ->
- Acc
+ <<"">> ->
+ case Acc of
+ {result, Features} -> {result, [?NS_VCARD | Features]};
+ empty -> {result, [?NS_VCARD]}
+ end;
+ _ -> Acc
end.
-process_local_iq(_From, _To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) ->
+process_local_iq(_From, _To,
+ #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) ->
case Type of
- set ->
- IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
- get ->
- IQ#iq{type = result,
- sub_el = [{xmlelement, "vCard",
- [{"xmlns", ?NS_VCARD}],
- [{xmlelement, "FN", [],
- [{xmlcdata, "ejabberd"}]},
- {xmlelement, "URL", [],
- [{xmlcdata, ?EJABBERD_URI}]},
- {xmlelement, "DESC", [],
- [{xmlcdata,
- translate:translate(
- Lang,
- "Erlang Jabber Server") ++
- "\nCopyright (c) 2002-2013 ProcessOne"}]},
- {xmlelement, "BDAY", [],
- [{xmlcdata, "2002-11-16"}]}
- ]}]}
+ set ->
+ IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
+ get ->
+ IQ#iq{type = result,
+ sub_el =
+ [#xmlel{name = <<"vCard">>,
+ attrs = [{<<"xmlns">>, ?NS_VCARD}],
+ children =
+ [#xmlel{name = <<"FN">>, attrs = [],
+ children =
+ [{xmlcdata, <<"ejabberd">>}]},
+ #xmlel{name = <<"URL">>, attrs = [],
+ children = [{xmlcdata, ?EJABBERD_URI}]},
+ #xmlel{name = <<"DESC">>, attrs = [],
+ children =
+ [{xmlcdata,
+ <<(translate:translate(Lang,
+ <<"Erlang Jabber Server">>))/binary,
+ "\nCopyright (c) 2002-2013 ProcessOne">>}]},
+ #xmlel{name = <<"BDAY">>, attrs = [],
+ children =
+ [{xmlcdata, <<"2002-11-16">>}]}]}]}
end.
-process_sm_iq(_From, #jid{lserver=LServer} = To, #iq{sub_el = SubEl} = IQ) ->
+process_sm_iq(_From, #jid{lserver = LServer} = To,
+ #iq{sub_el = SubEl} = IQ) ->
case catch process_vcard_ldap(To, IQ, LServer) of
- {'EXIT', _} ->
- IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]};
- Other ->
- Other
+ {'EXIT', _} ->
+ IQ#iq{type = error,
+ sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]};
+ Other -> Other
end.
process_vcard_ldap(To, IQ, Server) ->
{ok, State} = eldap_utils:get_state(Server, ?PROCNAME),
#iq{type = Type, sub_el = SubEl} = IQ,
case Type of
- set ->
- IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
- get ->
- #jid{luser = LUser} = To,
- LServer = State#state.serverhost,
- case ejabberd_auth:is_user_exists(LUser, LServer) of
- true ->
- VCardMap = State#state.vcard_map,
- case find_ldap_user(LUser, State) of
- #eldap_entry{attributes = Attributes} ->
- Vcard = ldap_attributes_to_vcard(Attributes, VCardMap, {LUser, LServer}),
- IQ#iq{type = result, sub_el = Vcard};
- _ ->
- IQ#iq{type = result, sub_el = []}
- end;
- _ ->
- IQ#iq{type = result, sub_el = []}
- end
- end.
+ set ->
+ IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
+ get ->
+ #jid{luser = LUser} = To,
+ LServer = State#state.serverhost,
+ case ejabberd_auth:is_user_exists(LUser, LServer) of
+ true ->
+ VCardMap = State#state.vcard_map,
+ case find_ldap_user(LUser, State) of
+ #eldap_entry{attributes = Attributes} ->
+ Vcard = ldap_attributes_to_vcard(Attributes, VCardMap,
+ {LUser, LServer}),
+ IQ#iq{type = result, sub_el = Vcard};
+ _ -> IQ#iq{type = result, sub_el = []}
+ end;
+ _ -> IQ#iq{type = result, sub_el = []}
+ end
+ end.
handle_call(get_state, _From, State) ->
{reply, {ok, State}, State};
@@ -286,124 +270,167 @@ find_ldap_user(User, State) ->
RFC2254_Filter = State#state.user_filter,
Eldap_ID = State#state.eldap_id,
VCardAttrs = State#state.vcard_map_attrs,
- case eldap_filter:parse(RFC2254_Filter, [{"%u", User}]) of
- {ok, EldapFilter} ->
- case eldap_pool:search(Eldap_ID,
- [{base, Base},
- {filter, EldapFilter},
- {deref_aliases, State#state.deref_aliases},
- {attributes, VCardAttrs}]) of
- #eldap_search_result{entries = [E | _]} ->
- E;
- _ ->
- false
- end;
- _ ->
- false
+ case eldap_filter:parse(RFC2254_Filter,
+ [{<<"%u">>, User}])
+ of
+ {ok, EldapFilter} ->
+ case eldap_pool:search(Eldap_ID,
+ [{base, Base}, {filter, EldapFilter},
+ {deref_aliases, State#state.deref_aliases},
+ {attributes, VCardAttrs}])
+ of
+ #eldap_search_result{entries = [E | _]} -> E;
+ _ -> false
+ end;
+ _ -> false
end.
ldap_attributes_to_vcard(Attributes, VCardMap, UD) ->
- Attrs = lists:map(
- fun({VCardName, _, _}) ->
- {stringprep:tolower(VCardName),
- map_vcard_attr(VCardName, Attributes, VCardMap, UD)}
- end, VCardMap),
- Elts = [ldap_attribute_to_vcard(vCard, Attr) || Attr <- Attrs],
- NElts = [ldap_attribute_to_vcard(vCardN, Attr) || Attr <- Attrs],
- OElts = [ldap_attribute_to_vcard(vCardO, Attr) || Attr <- Attrs],
- AElts = [ldap_attribute_to_vcard(vCardA, Attr) || Attr <- Attrs],
- [{xmlelement, "vCard", [{"xmlns", ?NS_VCARD}],
- lists:append([X || X <- Elts, X /= none],
- [{xmlelement,"N",[], [X || X <- NElts, X /= none]},
- {xmlelement,"ORG",[], [X || X <- OElts, X /= none]},
- {xmlelement,"ADR",[], [X || X <- AElts, X /= none]}])
- }].
-
-ldap_attribute_to_vcard(vCard, {"fn", Value}) ->
- {xmlelement,"FN",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCard, {"nickname", Value}) ->
- {xmlelement,"NICKNAME",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCard, {"title", Value}) ->
- {xmlelement,"TITLE",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCard, {"bday", Value}) ->
- {xmlelement,"BDAY",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCard, {"url", Value}) ->
- {xmlelement,"URL",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCard, {"desc", Value}) ->
- {xmlelement,"DESC",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCard, {"role", Value}) ->
- {xmlelement,"ROLE",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCard, {"tel", Value}) ->
- {xmlelement,"TEL",[],[{xmlelement,"VOICE",[],[]},
- {xmlelement,"WORK",[],[]},
- {xmlelement,"NUMBER",[],[{xmlcdata,Value}]}]};
-
-ldap_attribute_to_vcard(vCard, {"email", Value}) ->
- {xmlelement,"EMAIL",[],[{xmlelement,"INTERNET",[],[]},
- {xmlelement,"PREF",[],[]},
- {xmlelement,"USERID",[],[{xmlcdata,Value}]}]};
-
-ldap_attribute_to_vcard(vCard, {"photo", Value}) ->
- {xmlelement,"PHOTO",[],[
- {xmlelement,"TYPE",[],[{xmlcdata,"image/jpeg"}]},
- {xmlelement,"BINVAL",[],[{xmlcdata, jlib:encode_base64(Value)}]}]};
-
-ldap_attribute_to_vcard(vCardN, {"family", Value}) ->
- {xmlelement,"FAMILY",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCardN, {"given", Value}) ->
- {xmlelement,"GIVEN",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCardN, {"middle", Value}) ->
- {xmlelement,"MIDDLE",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCardO, {"orgname", Value}) ->
- {xmlelement,"ORGNAME",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCardO, {"orgunit", Value}) ->
- {xmlelement,"ORGUNIT",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCardA, {"locality", Value}) ->
- {xmlelement,"LOCALITY",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCardA, {"street", Value}) ->
- {xmlelement,"STREET",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCardA, {"ctry", Value}) ->
- {xmlelement,"CTRY",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCardA, {"region", Value}) ->
- {xmlelement,"REGION",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(vCardA, {"pcode", Value}) ->
- {xmlelement,"PCODE",[],[{xmlcdata,Value}]};
-
-ldap_attribute_to_vcard(_, _) ->
- none.
+ Attrs = lists:map(fun ({VCardName, _, _}) ->
+ {stringprep:tolower(VCardName),
+ map_vcard_attr(VCardName, Attributes, VCardMap,
+ UD)}
+ end,
+ VCardMap),
+ Elts = [ldap_attribute_to_vcard(vCard, Attr)
+ || Attr <- Attrs],
+ NElts = [ldap_attribute_to_vcard(vCardN, Attr)
+ || Attr <- Attrs],
+ OElts = [ldap_attribute_to_vcard(vCardO, Attr)
+ || Attr <- Attrs],
+ AElts = [ldap_attribute_to_vcard(vCardA, Attr)
+ || Attr <- Attrs],
+ [#xmlel{name = <<"vCard">>,
+ attrs = [{<<"xmlns">>, ?NS_VCARD}],
+ children =
+ lists:append([X || X <- Elts, X /= none],
+ [#xmlel{name = <<"N">>, attrs = [],
+ children = [X || X <- NElts, X /= none]},
+ #xmlel{name = <<"ORG">>, attrs = [],
+ children = [X || X <- OElts, X /= none]},
+ #xmlel{name = <<"ADR">>, attrs = [],
+ children =
+ [X || X <- AElts, X /= none]}])}].
+
+ldap_attribute_to_vcard(vCard, {<<"fn">>, Value}) ->
+ #xmlel{name = <<"FN">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCard,
+ {<<"nickname">>, Value}) ->
+ #xmlel{name = <<"NICKNAME">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCard, {<<"title">>, Value}) ->
+ #xmlel{name = <<"TITLE">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCard, {<<"bday">>, Value}) ->
+ #xmlel{name = <<"BDAY">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCard, {<<"url">>, Value}) ->
+ #xmlel{name = <<"URL">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCard, {<<"desc">>, Value}) ->
+ #xmlel{name = <<"DESC">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCard, {<<"role">>, Value}) ->
+ #xmlel{name = <<"ROLE">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCard, {<<"tel">>, Value}) ->
+ #xmlel{name = <<"TEL">>, attrs = [],
+ children =
+ [#xmlel{name = <<"VOICE">>, attrs = [], children = []},
+ #xmlel{name = <<"WORK">>, attrs = [], children = []},
+ #xmlel{name = <<"NUMBER">>, attrs = [],
+ children = [{xmlcdata, Value}]}]};
+ldap_attribute_to_vcard(vCard, {<<"email">>, Value}) ->
+ #xmlel{name = <<"EMAIL">>, attrs = [],
+ children =
+ [#xmlel{name = <<"INTERNET">>, attrs = [],
+ children = []},
+ #xmlel{name = <<"PREF">>, attrs = [], children = []},
+ #xmlel{name = <<"USERID">>, attrs = [],
+ children = [{xmlcdata, Value}]}]};
+ldap_attribute_to_vcard(vCard, {<<"photo">>, Value}) ->
+ #xmlel{name = <<"PHOTO">>, attrs = [],
+ children =
+ [#xmlel{name = <<"TYPE">>, attrs = [],
+ children = [{xmlcdata, <<"image/jpeg">>}]},
+ #xmlel{name = <<"BINVAL">>, attrs = [],
+ children = [{xmlcdata, jlib:encode_base64(Value)}]}]};
+ldap_attribute_to_vcard(vCardN,
+ {<<"family">>, Value}) ->
+ #xmlel{name = <<"FAMILY">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCardN, {<<"given">>, Value}) ->
+ #xmlel{name = <<"GIVEN">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCardN,
+ {<<"middle">>, Value}) ->
+ #xmlel{name = <<"MIDDLE">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCardO,
+ {<<"orgname">>, Value}) ->
+ #xmlel{name = <<"ORGNAME">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCardO,
+ {<<"orgunit">>, Value}) ->
+ #xmlel{name = <<"ORGUNIT">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCardA,
+ {<<"locality">>, Value}) ->
+ #xmlel{name = <<"LOCALITY">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCardA,
+ {<<"street">>, Value}) ->
+ #xmlel{name = <<"STREET">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCardA, {<<"ctry">>, Value}) ->
+ #xmlel{name = <<"CTRY">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCardA,
+ {<<"region">>, Value}) ->
+ #xmlel{name = <<"REGION">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(vCardA, {<<"pcode">>, Value}) ->
+ #xmlel{name = <<"PCODE">>, attrs = [],
+ children = [{xmlcdata, Value}]};
+ldap_attribute_to_vcard(_, _) -> none.
-define(TLFIELD(Type, Label, Var),
- {xmlelement, "field", [{"type", Type},
- {"label", translate:translate(Lang, Label)},
- {"var", Var}], []}).
+ #xmlel{name = <<"field">>,
+ attrs =
+ [{<<"type">>, Type},
+ {<<"label">>, translate:translate(Lang, Label)},
+ {<<"var">>, Var}],
+ children = []}).
-define(FORM(JID, SearchFields),
- [{xmlelement, "instructions", [],
- [{xmlcdata, translate:translate(Lang, "You need an x:data capable client to search")}]},
- {xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
- [{xmlelement, "title", [],
- [{xmlcdata, translate:translate(Lang, "Search users in ") ++
- jlib:jid_to_string(JID)}]},
- {xmlelement, "instructions", [],
- [{xmlcdata, translate:translate(Lang, "Fill in fields to search "
- "for any matching Jabber User")}]}
- ] ++ lists:map(fun({X,Y}) -> ?TLFIELD("text-single", X, Y) end, SearchFields)}]).
+ [#xmlel{name = <<"instructions">>, attrs = [],
+ children =
+ [{xmlcdata,
+ translate:translate(Lang,
+ <<"You need an x:data capable client to "
+ "search">>)}]},
+ #xmlel{name = <<"x">>,
+ attrs =
+ [{<<"xmlns">>, ?NS_XDATA}, {<<"type">>, <<"form">>}],
+ children =
+ [#xmlel{name = <<"title">>, attrs = [],
+ children =
+ [{xmlcdata,
+ <<(translate:translate(Lang,
+ <<"Search users in ">>))/binary,
+ (jlib:jid_to_string(JID))/binary>>}]},
+ #xmlel{name = <<"instructions">>, attrs = [],
+ children =
+ [{xmlcdata,
+ translate:translate(Lang,
+ <<"Fill in fields to search for any matching "
+ "Jabber User">>)}]}]
+ ++
+ lists:map(fun ({X, Y}) ->
+ ?TLFIELD(<<"text-single">>, X, Y)
+ end,
+ SearchFields)}]).
do_route(State, From, To, Packet) ->
spawn(?MODULE, route, [State, From, To, Packet]).
@@ -411,162 +438,186 @@ do_route(State, From, To, Packet) ->
route(State, From, To, Packet) ->
#jid{user = User, resource = Resource} = To,
ServerHost = State#state.serverhost,
- if
- (User /= "") or (Resource /= "") ->
- Err = jlib:make_error_reply(Packet, ?ERR_SERVICE_UNAVAILABLE),
- ejabberd_router:route(To, From, Err);
- true ->
- IQ = jlib:iq_query_info(Packet),
- case IQ of
- #iq{type = Type, xmlns = ?NS_SEARCH, lang = Lang, sub_el = SubEl} ->
- case Type of
- set ->
- XDataEl = find_xdata_el(SubEl),
- case XDataEl of
- false ->
- Err = jlib:make_error_reply(
- Packet, ?ERR_BAD_REQUEST),
- ejabberd_router:route(To, From, Err);
- _ ->
- XData = jlib:parse_xdata_submit(XDataEl),
- case XData of
- invalid ->
- Err = jlib:make_error_reply(
- Packet,
- ?ERR_BAD_REQUEST),
- ejabberd_router:route(To, From,
- Err);
- _ ->
- ResIQ =
- IQ#iq{
- type = result,
- sub_el =
- [{xmlelement,
- "query",
- [{"xmlns", ?NS_SEARCH}],
- [{xmlelement, "x",
- [{"xmlns", ?NS_XDATA},
- {"type", "result"}],
- search_result(Lang, To, State, XData)
- }]}]},
- ejabberd_router:route(
- To, From, jlib:iq_to_xml(ResIQ))
- end
- end;
- get ->
- SearchFields = State#state.search_fields,
- ResIQ = IQ#iq{type = result,
- sub_el = [{xmlelement,
- "query",
- [{"xmlns", ?NS_SEARCH}],
- ?FORM(To, SearchFields)
- }]},
- ejabberd_router:route(To,
- From,
- jlib:iq_to_xml(ResIQ))
- end;
- #iq{type = Type, xmlns = ?NS_DISCO_INFO, lang = Lang} ->
- case Type of
- set ->
- Err = jlib:make_error_reply(
- Packet, ?ERR_NOT_ALLOWED),
- ejabberd_router:route(To, From, Err);
- get ->
- Info = ejabberd_hooks:run_fold(
- disco_info, ServerHost, [],
- [ServerHost, ?MODULE, "", ""]),
- ResIQ =
- IQ#iq{type = result,
- sub_el = [{xmlelement,
- "query",
- [{"xmlns", ?NS_DISCO_INFO}],
- [{xmlelement, "identity",
- [{"category", "directory"},
- {"type", "user"},
- {"name",
- translate:translate(Lang, "vCard User Search")}],
- []},
- {xmlelement, "feature",
- [{"var", ?NS_SEARCH}], []},
- {xmlelement, "feature",
- [{"var", ?NS_VCARD}], []}
- ] ++ Info
- }]},
- ejabberd_router:route(To,
- From,
- jlib:iq_to_xml(ResIQ))
- end;
- #iq{type = Type, xmlns = ?NS_DISCO_ITEMS} ->
- case Type of
- set ->
- Err = jlib:make_error_reply(
- Packet, ?ERR_NOT_ALLOWED),
- ejabberd_router:route(To, From, Err);
- get ->
- ResIQ =
- IQ#iq{type = result,
- sub_el = [{xmlelement,
- "query",
- [{"xmlns", ?NS_DISCO_ITEMS}],
- []}]},
- ejabberd_router:route(To,
- From,
- jlib:iq_to_xml(ResIQ))
- end;
- #iq{type = get, xmlns = ?NS_VCARD, lang = Lang} ->
- ResIQ =
- IQ#iq{type = result,
- sub_el = [{xmlelement,
- "vCard",
- [{"xmlns", ?NS_VCARD}],
- iq_get_vcard(Lang)}]},
- ejabberd_router:route(To,
- From,
- jlib:iq_to_xml(ResIQ));
- _ ->
- Err = jlib:make_error_reply(Packet,
- ?ERR_SERVICE_UNAVAILABLE),
- ejabberd_router:route(To, From, Err)
- end
+ if (User /= <<"">>) or (Resource /= <<"">>) ->
+ Err = jlib:make_error_reply(Packet,
+ ?ERR_SERVICE_UNAVAILABLE),
+ ejabberd_router:route(To, From, Err);
+ true ->
+ IQ = jlib:iq_query_info(Packet),
+ case IQ of
+ #iq{type = Type, xmlns = ?NS_SEARCH, lang = Lang,
+ sub_el = SubEl} ->
+ case Type of
+ set ->
+ XDataEl = find_xdata_el(SubEl),
+ case XDataEl of
+ false ->
+ Err = jlib:make_error_reply(Packet,
+ ?ERR_BAD_REQUEST),
+ ejabberd_router:route(To, From, Err);
+ _ ->
+ XData = jlib:parse_xdata_submit(XDataEl),
+ case XData of
+ invalid ->
+ Err = jlib:make_error_reply(Packet,
+ ?ERR_BAD_REQUEST),
+ ejabberd_router:route(To, From, Err);
+ _ ->
+ ResIQ = IQ#iq{type = result,
+ sub_el =
+ [#xmlel{name = <<"query">>,
+ attrs =
+ [{<<"xmlns">>,
+ ?NS_SEARCH}],
+ children =
+ [#xmlel{name =
+ <<"x">>,
+ attrs =
+ [{<<"xmlns">>,
+ ?NS_XDATA},
+ {<<"type">>,
+ <<"result">>}],
+ children
+ =
+ search_result(Lang,
+ To,
+ State,
+ XData)}]}]},
+ ejabberd_router:route(To, From,
+ jlib:iq_to_xml(ResIQ))
+ end
+ end;
+ get ->
+ SearchFields = State#state.search_fields,
+ ResIQ = IQ#iq{type = result,
+ sub_el =
+ [#xmlel{name = <<"query">>,
+ attrs =
+ [{<<"xmlns">>,
+ ?NS_SEARCH}],
+ children =
+ ?FORM(To, SearchFields)}]},
+ ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ))
+ end;
+ #iq{type = Type, xmlns = ?NS_DISCO_INFO, lang = Lang} ->
+ case Type of
+ set ->
+ Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
+ ejabberd_router:route(To, From, Err);
+ get ->
+ Info = ejabberd_hooks:run_fold(disco_info, ServerHost,
+ [],
+ [ServerHost, ?MODULE,
+ <<"">>, <<"">>]),
+ ResIQ = IQ#iq{type = result,
+ sub_el =
+ [#xmlel{name = <<"query">>,
+ attrs =
+ [{<<"xmlns">>,
+ ?NS_DISCO_INFO}],
+ children =
+ [#xmlel{name =
+ <<"identity">>,
+ attrs =
+ [{<<"category">>,
+ <<"directory">>},
+ {<<"type">>,
+ <<"user">>},
+ {<<"name">>,
+ translate:translate(Lang,
+ <<"vCard User Search">>)}],
+ children = []},
+ #xmlel{name =
+ <<"feature">>,
+ attrs =
+ [{<<"var">>,
+ ?NS_SEARCH}],
+ children = []},
+ #xmlel{name =
+ <<"feature">>,
+ attrs =
+ [{<<"var">>,
+ ?NS_VCARD}],
+ children = []}]
+ ++ Info}]},
+ ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ))
+ end;
+ #iq{type = Type, xmlns = ?NS_DISCO_ITEMS} ->
+ case Type of
+ set ->
+ Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
+ ejabberd_router:route(To, From, Err);
+ get ->
+ ResIQ = IQ#iq{type = result,
+ sub_el =
+ [#xmlel{name = <<"query">>,
+ attrs =
+ [{<<"xmlns">>,
+ ?NS_DISCO_ITEMS}],
+ children = []}]},
+ ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ))
+ end;
+ #iq{type = get, xmlns = ?NS_VCARD, lang = Lang} ->
+ ResIQ = IQ#iq{type = result,
+ sub_el =
+ [#xmlel{name = <<"vCard">>,
+ attrs = [{<<"xmlns">>, ?NS_VCARD}],
+ children = iq_get_vcard(Lang)}]},
+ ejabberd_router:route(To, From, jlib:iq_to_xml(ResIQ));
+ _ ->
+ Err = jlib:make_error_reply(Packet,
+ ?ERR_SERVICE_UNAVAILABLE),
+ ejabberd_router:route(To, From, Err)
+ end
end.
iq_get_vcard(Lang) ->
- [{xmlelement, "FN", [],
- [{xmlcdata, "ejabberd/mod_vcard"}]},
- {xmlelement, "URL", [],
- [{xmlcdata, ?EJABBERD_URI}]},
- {xmlelement, "DESC", [],
- [{xmlcdata, translate:translate(
- Lang,
- "ejabberd vCard module") ++
- "\nCopyright (c) 2003-2013 ProcessOne"}]}].
+ [#xmlel{name = <<"FN">>, attrs = [],
+ children = [{xmlcdata, <<"ejabberd/mod_vcard">>}]},
+ #xmlel{name = <<"URL">>, attrs = [],
+ children = [{xmlcdata, ?EJABBERD_URI}]},
+ #xmlel{name = <<"DESC">>, attrs = [],
+ children =
+ [{xmlcdata,
+ <<(translate:translate(Lang,
+ <<"ejabberd vCard module">>))/binary,
+ "\nCopyright (c) 2003-2013 ProcessOne">>}]}].
-define(LFIELD(Label, Var),
- {xmlelement, "field", [{"label", translate:translate(Lang, Label)},
- {"var", Var}], []}).
+ #xmlel{name = <<"field">>,
+ attrs =
+ [{<<"label">>, translate:translate(Lang, Label)},
+ {<<"var">>, Var}],
+ children = []}).
search_result(Lang, JID, State, Data) ->
SearchReported = State#state.search_reported,
- Header = [{xmlelement, "title", [],
- [{xmlcdata, translate:translate(Lang, "Search Results for ") ++
- jlib:jid_to_string(JID)}]},
- {xmlelement, "reported", [],
- [?TLFIELD("text-single", "Jabber ID", "jid")] ++
- lists:map(
- fun({Name, Value}) -> ?TLFIELD("text-single", Name, Value) end,
- SearchReported)
- }],
+ Header = [#xmlel{name = <<"title">>, attrs = [],
+ children =
+ [{xmlcdata,
+ <<(translate:translate(Lang,
+ <<"Search Results for ">>))/binary,
+ (jlib:jid_to_string(JID))/binary>>}]},
+ #xmlel{name = <<"reported">>, attrs = [],
+ children =
+ [?TLFIELD(<<"text-single">>, <<"Jabber ID">>,
+ <<"jid">>)]
+ ++
+ lists:map(fun ({Name, Value}) ->
+ ?TLFIELD(<<"text-single">>, Name,
+ Value)
+ end,
+ SearchReported)}],
case search(State, Data) of
- error ->
- Header;
- Result ->
- Header ++ Result
+ error -> Header;
+ Result -> Header ++ Result
end.
-define(FIELD(Var, Val),
- {xmlelement, "field", [{"var", Var}],
- [{xmlelement, "value", [],
- [{xmlcdata, Val}]}]}).
+ #xmlel{name = <<"field">>, attrs = [{<<"var">>, Var}],
+ children =
+ [#xmlel{name = <<"value">>, attrs = [],
+ children = [{xmlcdata, Val}]}]}).
search(State, Data) ->
Base = State#state.base,
@@ -575,247 +626,203 @@ search(State, Data) ->
UIDs = State#state.uids,
Limit = State#state.matches,
ReportedAttrs = State#state.search_reported_attrs,
- Filter = eldap:'and'([SearchFilter, eldap_utils:make_filter(Data, UIDs)]),
+ Filter = eldap:'and'([SearchFilter,
+ eldap_utils:make_filter(Data, UIDs)]),
case eldap_pool:search(Eldap_ID,
- [{base, Base},
- {filter, Filter},
- {limit, Limit},
- {deref_aliases, State#state.deref_aliases},
- {attributes, ReportedAttrs}]) of
- #eldap_search_result{entries = E} ->
- search_items(E, State);
- _ ->
- error
+ [{base, Base}, {filter, Filter}, {limit, Limit},
+ {deref_aliases, State#state.deref_aliases},
+ {attributes, ReportedAttrs}])
+ of
+ #eldap_search_result{entries = E} ->
+ search_items(E, State);
+ _ -> error
end.
search_items(Entries, State) ->
LServer = State#state.serverhost,
SearchReported = State#state.search_reported,
VCardMap = State#state.vcard_map,
- UIDs = State#state.uids,
- Attributes = lists:map(
- fun(E) ->
- #eldap_entry{attributes = Attrs} = E,
- Attrs
- end, Entries),
- lists:flatmap(
- fun(Attrs) ->
- case eldap_utils:find_ldap_attrs(UIDs, Attrs) of
- {U, UIDAttrFormat} ->
- case eldap_utils:get_user_part(U, UIDAttrFormat) of
- {ok, Username} ->
- case ejabberd_auth:is_user_exists(Username, LServer) of
- true ->
- RFields = lists:map(
- fun({_, VCardName}) ->
- {VCardName,
- map_vcard_attr(
- VCardName,
- Attrs,
- VCardMap,
- {Username, ?MYNAME})}
- end, SearchReported),
- Result = [?FIELD("jid", Username ++ "@" ++ LServer)] ++
- [?FIELD(Name, Value) || {Name, Value} <- RFields],
- [{xmlelement, "item", [], Result}];
- _ ->
- []
- end;
- _ ->
- []
- end;
- "" ->
- []
- end
- end, Attributes).
-
-remove_user(_User) ->
- true.
+ UIDs = State#state.uids,
+ Attributes = lists:map(fun (E) ->
+ #eldap_entry{attributes = Attrs} = E, Attrs
+ end,
+ Entries),
+ lists:flatmap(fun (Attrs) ->
+ case eldap_utils:find_ldap_attrs(UIDs, Attrs) of
+ {U, UIDAttrFormat} ->
+ case eldap_utils:get_user_part(U, UIDAttrFormat)
+ of
+ {ok, Username} ->
+ case
+ ejabberd_auth:is_user_exists(Username,
+ LServer)
+ of
+ true ->
+ RFields = lists:map(fun ({_,
+ VCardName}) ->
+ {VCardName,
+ map_vcard_attr(VCardName,
+ Attrs,
+ VCardMap,
+ {Username,
+ ?MYNAME})}
+ end,
+ SearchReported),
+ Result = [?FIELD(<<"jid">>,
+ <<Username/binary,
+ "@",
+ LServer/binary>>)]
+ ++
+ [?FIELD(Name, Value)
+ || {Name, Value}
+ <- RFields],
+ [#xmlel{name = <<"item">>,
+ attrs = [],
+ children = Result}];
+ _ -> []
+ end;
+ _ -> []
+ end;
+ <<"">> -> []
+ end
+ end,
+ Attributes).
+
+remove_user(_User) -> true.
%%%-----------------------
%%% Auxiliary functions.
%%%-----------------------
map_vcard_attr(VCardName, Attributes, Pattern, UD) ->
- Res = lists:filter(
- fun({Name, _, _}) ->
- eldap_utils:case_insensitive_match(Name, VCardName)
- end, Pattern),
+ Res = lists:filter(fun ({Name, _, _}) ->
+ eldap_utils:case_insensitive_match(Name,
+ VCardName)
+ end,
+ Pattern),
case Res of
- [{_, Str, Attrs}] ->
- process_pattern(Str, UD,
- [eldap_utils:get_ldap_attr(X, Attributes) || X<-Attrs]);
- _ -> ""
+ [{_, Str, Attrs}] ->
+ process_pattern(Str, UD,
+ [eldap_utils:get_ldap_attr(X, Attributes)
+ || X <- Attrs]);
+ _ -> <<"">>
end.
process_pattern(Str, {User, Domain}, AttrValues) ->
- eldap_filter:do_sub(
- Str,
- [{"%u", User},{"%d", Domain}] ++
- [{"%s", V, 1} || V <- AttrValues]).
+ eldap_filter:do_sub(Str,
+ [{<<"%u">>, User}, {<<"%d">>, Domain}] ++
+ [{<<"%s">>, V, 1} || V <- AttrValues]).
-find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) ->
+find_xdata_el(#xmlel{children = SubEls}) ->
find_xdata_el1(SubEls).
-find_xdata_el1([]) ->
- false;
-find_xdata_el1([{xmlelement, Name, Attrs, SubEls} | Els]) ->
- case xml:get_attr_s("xmlns", Attrs) of
- ?NS_XDATA ->
- {xmlelement, Name, Attrs, SubEls};
- _ ->
- find_xdata_el1(Els)
+find_xdata_el1([]) -> false;
+find_xdata_el1([#xmlel{name = Name, attrs = Attrs,
+ children = SubEls}
+ | Els]) ->
+ case xml:get_attr_s(<<"xmlns">>, Attrs) of
+ ?NS_XDATA ->
+ #xmlel{name = Name, attrs = Attrs, children = SubEls};
+ _ -> find_xdata_el1(Els)
end;
-find_xdata_el1([_ | Els]) ->
- find_xdata_el1(Els).
+find_xdata_el1([_ | Els]) -> find_xdata_el1(Els).
parse_options(Host, Opts) ->
- MyHost = gen_mod:get_opt_host(Host, Opts, "vjud.@HOST@"),
- Search = gen_mod:get_opt(search, Opts, true),
- Matches = case gen_mod:get_opt(matches, Opts, 30) of
- infinity -> 0;
- N -> N
- end,
- Eldap_ID = atom_to_list(gen_mod:get_module_proc(Host, ?PROCNAME)),
- LDAPServers = case gen_mod:get_opt(ldap_servers, Opts, undefined) of
- undefined ->
- ejabberd_config:get_local_option({ldap_servers, Host});
- S -> S
- end,
- LDAPBackups = case gen_mod:get_opt(ldap_backups, Opts, undefined) of
- undefined ->
- ejabberd_config:get_local_option({ldap_servers, Host});
- Backups -> Backups
- end,
- LDAPEncrypt = case gen_mod:get_opt(ldap_encrypt, Opts, undefined) of
- undefined ->
- ejabberd_config:get_local_option({ldap_encrypt, Host});
- E -> E
- end,
- LDAPTLSVerify = case gen_mod:get_opt(ldap_tls_verify, Opts, undefined) of
- undefined ->
- ejabberd_config:get_local_option({ldap_tls_verify, Host});
- Verify -> Verify
- end,
- LDAPTLSCAFile = case gen_mod:get_opt(ldap_tls_cacertfile, Opts, undefined) of
- undefined ->
- ejabberd_config:get_local_option({ldap_tls_cacertfile, Host});
- CAFile -> CAFile
- end,
- LDAPTLSDepth = case gen_mod:get_opt(ldap_tls_depth, Opts, undefined) of
- undefined ->
- ejabberd_config:get_local_option({ldap_tls_depth, Host});
- Depth ->
- Depth
- end,
- LDAPPortTemp = case gen_mod:get_opt(ldap_port, Opts, undefined) of
- undefined ->
- ejabberd_config:get_local_option({ldap_port, Host});
- PT -> PT
- end,
- LDAPPort = case LDAPPortTemp of
- undefined ->
- case LDAPEncrypt of
- tls -> ?LDAPS_PORT;
- starttls -> ?LDAP_PORT;
- _ -> ?LDAP_PORT
- end;
- P -> P
- end,
- LDAPBase = case gen_mod:get_opt(ldap_base, Opts, undefined) of
- undefined ->
- ejabberd_config:get_local_option({ldap_base, Host});
- B -> B
- end,
- UIDs = case gen_mod:get_opt(ldap_uids, Opts, undefined) of
- undefined ->
- case ejabberd_config:get_local_option({ldap_uids, Host}) of
- undefined -> [{"uid", "%u"}];
- UI -> eldap_utils:uids_domain_subst(Host, UI)
- end;
- UI -> eldap_utils:uids_domain_subst(Host, UI)
- end,
- RootDN = case gen_mod:get_opt(ldap_rootdn, Opts, undefined) of
- undefined ->
- case ejabberd_config:get_local_option({ldap_rootdn, Host}) of
- undefined -> "";
- RDN -> RDN
- end;
- RDN -> RDN
- end,
- Password = case gen_mod:get_opt(ldap_password, Opts, undefined) of
- undefined ->
- case ejabberd_config:get_local_option({ldap_password, Host}) of
- undefined -> "";
- Pass -> Pass
- end;
- Pass -> Pass
- end,
- SubFilter = lists:flatten(eldap_utils:generate_subfilter(UIDs)),
- UserFilter = case gen_mod:get_opt(ldap_filter, Opts, undefined) of
- undefined ->
- case ejabberd_config:get_local_option({ldap_filter, Host}) of
- undefined -> SubFilter;
- "" -> SubFilter;
- F ->
- eldap_utils:check_filter(F),
- "(&" ++ SubFilter ++ F ++ ")"
- end;
- "" -> SubFilter;
- F ->
- eldap_utils:check_filter(F),
- "(&" ++ SubFilter ++ F ++ ")"
- end,
- {ok, SearchFilter} = eldap_filter:parse(
- eldap_filter:do_sub(UserFilter, [{"%u","*"}])),
- VCardMap = gen_mod:get_opt(ldap_vcard_map, Opts, ?VCARD_MAP),
- SearchFields = gen_mod:get_opt(ldap_search_fields, Opts, ?SEARCH_FIELDS),
- SearchReported = gen_mod:get_opt(ldap_search_reported, Opts, ?SEARCH_REPORTED),
- %% In search requests we need to fetch only attributes defined
- %% in vcard-map and search-reported. In some cases,
- %% this will essentially reduce network traffic from an LDAP server.
- UIDAttrs = [UAttr || {UAttr, _} <- UIDs],
- VCardMapAttrs = lists:usort(
- lists:append([A || {_, _, A} <- VCardMap]) ++ UIDAttrs),
- SearchReportedAttrs =
- lists:usort(lists:flatmap(
- fun({_, N}) ->
- case lists:keysearch(N, 1, VCardMap) of
- {value, {_, _, L}} -> L;
- _ -> []
- end
- end, SearchReported) ++ UIDAttrs),
- DerefAliases = case gen_mod:get_opt(deref_aliases, Opts, undefined) of
- undefined ->
- case ejabberd_config:get_local_option(
- {deref_aliases, Host}) of
- undefined -> never;
- D -> D
- end;
- D -> D
- end,
- #state{serverhost = Host,
- myhost = MyHost,
- eldap_id = Eldap_ID,
- search = Search,
- servers = LDAPServers,
- backups = LDAPBackups,
- port = LDAPPort,
- tls_options = [{encrypt, LDAPEncrypt},
- {tls_verify, LDAPTLSVerify},
- {tls_cacertfile, LDAPTLSCAFile},
- {tls_depth, LDAPTLSDepth}],
- dn = RootDN,
- base = LDAPBase,
- password = Password,
- uids = UIDs,
- vcard_map = VCardMap,
+ MyHost = gen_mod:get_opt_host(Host, Opts,
+ <<"vjud.@HOST@">>),
+ Search = gen_mod:get_opt(search, Opts,
+ fun(B) when is_boolean(B) -> B end,
+ true),
+ Matches = gen_mod:get_opt(matches, Opts,
+ fun(infinity) -> 0;
+ (I) when is_integer(I), I>0 -> I
+ end, 30),
+ Eldap_ID = jlib:atom_to_binary(gen_mod:get_module_proc(Host, ?PROCNAME)),
+ Cfg = eldap_utils:get_config(Host, Opts),
+ UIDsTemp = eldap_utils:get_opt(
+ {ldap_uids, Host}, Opts,
+ fun(Us) ->
+ lists:map(
+ fun({U, P}) ->
+ {iolist_to_binary(U),
+ iolist_to_binary(P)};
+ ({U}) ->
+ {iolist_to_binary(U)}
+ end, Us)
+ end, [{<<"uid">>, <<"%u">>}]),
+ UIDs = eldap_utils:uids_domain_subst(Host, UIDsTemp),
+ SubFilter = eldap_utils:generate_subfilter(UIDs),
+ UserFilter = case eldap_utils:get_opt(
+ {ldap_filter, Host}, Opts,
+ fun check_filter/1, <<"">>) of
+ <<"">> ->
+ SubFilter;
+ F ->
+ <<"(&", SubFilter/binary, F/binary, ")">>
+ end,
+ {ok, SearchFilter} =
+ eldap_filter:parse(eldap_filter:do_sub(UserFilter,
+ [{<<"%u">>, <<"*">>}])),
+ VCardMap = gen_mod:get_opt(ldap_vcard_map, Opts,
+ fun(Ls) ->
+ lists:map(
+ fun({S, P, L}) ->
+ {iolist_to_binary(S),
+ iolist_to_binary(P),
+ [iolist_to_binary(E)
+ || E <- L]}
+ end, Ls)
+ end, ?VCARD_MAP),
+ SearchFields = gen_mod:get_opt(ldap_search_fields, Opts,
+ fun(Ls) ->
+ [{iolist_to_binary(S),
+ iolist_to_binary(P)}
+ || {S, P} <- Ls]
+ end, ?SEARCH_FIELDS),
+ SearchReported = gen_mod:get_opt(ldap_search_reported, Opts,
+ fun(Ls) ->
+ [{iolist_to_binary(S),
+ iolist_to_binary(P)}
+ || {S, P} <- Ls]
+ end, ?SEARCH_REPORTED),
+ UIDAttrs = [UAttr || {UAttr, _} <- UIDs],
+ VCardMapAttrs = lists:usort(lists:append([A
+ || {_, _, A} <- VCardMap])
+ ++ UIDAttrs),
+ SearchReportedAttrs = lists:usort(lists:flatmap(fun ({_,
+ N}) ->
+ case
+ lists:keysearch(N,
+ 1,
+ VCardMap)
+ of
+ {value,
+ {_, _, L}} ->
+ L;
+ _ -> []
+ end
+ end,
+ SearchReported)
+ ++ UIDAttrs),
+ #state{serverhost = Host, myhost = MyHost,
+ eldap_id = Eldap_ID, search = Search,
+ servers = Cfg#eldap_config.servers,
+ backups = Cfg#eldap_config.backups,
+ port = Cfg#eldap_config.port,
+ tls_options = Cfg#eldap_config.tls_options,
+ dn = Cfg#eldap_config.dn,
+ password = Cfg#eldap_config.password,
+ base = Cfg#eldap_config.base,
+ deref_aliases = Cfg#eldap_config.deref_aliases,
+ uids = UIDs, vcard_map = VCardMap,
vcard_map_attrs = VCardMapAttrs,
- user_filter = UserFilter,
- search_filter = SearchFilter,
+ user_filter = UserFilter, search_filter = SearchFilter,
search_fields = SearchFields,
search_reported = SearchReported,
search_reported_attrs = SearchReportedAttrs,
- deref_aliases = DerefAliases,
- matches = Matches
- }.
+ matches = Matches}.
+
+check_filter(F) ->
+ NewF = iolist_to_binary(F),
+ {ok, _} = eldap_filter:parse(NewF),
+ NewF.