diff options
author | Badlop <badlop@process-one.net> | 2013-03-14 10:33:02 +0100 |
---|---|---|
committer | Badlop <badlop@process-one.net> | 2013-03-14 10:33:02 +0100 |
commit | 9deb294328bb3f9eb6bd2c0e7cd500732e9b5830 (patch) | |
tree | 7e1066c130250627ee0abab44a135f583a28d07f /src/mod_vcard.erl | |
parent | list_to_integer/2 only works in OTP R14 and newer (diff) |
Accumulated patch to binarize and indent code
Diffstat (limited to '')
-rw-r--r-- | src/mod_vcard.erl | 1628 |
1 files changed, 810 insertions, 818 deletions
diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl index 3b70fe21f..901098398 100644 --- a/src/mod_vcard.erl +++ b/src/mod_vcard.erl @@ -25,644 +25,668 @@ %%%---------------------------------------------------------------------- -module(mod_vcard). + -author('alexey@process-one.net'). -behaviour(gen_mod). --export([start/2, init/3, stop/1, - get_sm_features/5, - process_local_iq/3, - process_sm_iq/3, - reindex_vcards/0, - remove_user/2]). +-export([start/2, init/3, stop/1, get_sm_features/5, + process_local_iq/3, process_sm_iq/3, reindex_vcards/0, + remove_user/2, export/1]). -include("ejabberd.hrl"). --include("jlib.hrl"). +-include("jlib.hrl"). -define(JUD_MATCHES, 30). --record(vcard_search, {us, - user, luser, - fn, lfn, - family, lfamily, - given, lgiven, - middle, lmiddle, - nickname, lnickname, - bday, lbday, - ctry, lctry, - locality, llocality, - email, lemail, - orgname, lorgname, - orgunit, lorgunit - }). --record(vcard, {us, vcard}). +-record(vcard_search, + {us, user, luser, fn, lfn, family, lfamily, given, + lgiven, middle, lmiddle, nickname, lnickname, bday, + lbday, ctry, lctry, locality, llocality, email, lemail, + orgname, lorgname, orgunit, lorgunit}). + +-record(vcard, {us = {<<"">>, <<"">>} :: {binary(), binary()}, + vcard = #xmlel{} :: xmlel()}). -define(PROCNAME, ejabberd_mod_vcard). start(Host, Opts) -> case gen_mod:db_type(Opts) of - mnesia -> - mnesia:create_table(vcard, - [{disc_only_copies, [node()]}, - {attributes, - record_info(fields, vcard)}]), - mnesia:create_table(vcard_search, - [{disc_copies, [node()]}, - {attributes, - record_info(fields, vcard_search)}]), - update_tables(), - mnesia:add_table_index(vcard_search, luser), - mnesia:add_table_index(vcard_search, lfn), - mnesia:add_table_index(vcard_search, lfamily), - mnesia:add_table_index(vcard_search, lgiven), - mnesia:add_table_index(vcard_search, lmiddle), - mnesia:add_table_index(vcard_search, lnickname), - mnesia:add_table_index(vcard_search, lbday), - mnesia:add_table_index(vcard_search, lctry), - mnesia:add_table_index(vcard_search, llocality), - mnesia:add_table_index(vcard_search, lemail), - mnesia:add_table_index(vcard_search, lorgname), - mnesia:add_table_index(vcard_search, lorgunit); - _ -> - ok + mnesia -> + mnesia:create_table(vcard, + [{disc_only_copies, [node()]}, + {attributes, record_info(fields, vcard)}]), + mnesia:create_table(vcard_search, + [{disc_copies, [node()]}, + {attributes, + record_info(fields, vcard_search)}]), + update_tables(), + mnesia:add_table_index(vcard_search, luser), + mnesia:add_table_index(vcard_search, lfn), + mnesia:add_table_index(vcard_search, lfamily), + mnesia:add_table_index(vcard_search, lgiven), + mnesia:add_table_index(vcard_search, lmiddle), + mnesia:add_table_index(vcard_search, lnickname), + mnesia:add_table_index(vcard_search, lbday), + mnesia:add_table_index(vcard_search, lctry), + mnesia:add_table_index(vcard_search, llocality), + mnesia:add_table_index(vcard_search, lemail), + mnesia:add_table_index(vcard_search, lorgname), + mnesia:add_table_index(vcard_search, lorgunit); + _ -> ok end, - ejabberd_hooks:add(remove_user, Host, - ?MODULE, remove_user, 50), - 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), - MyHost = gen_mod:get_opt_host(Host, Opts, "vjud.@HOST@"), - Search = gen_mod:get_opt(search, Opts, true), + ejabberd_hooks:add(remove_user, Host, ?MODULE, + remove_user, 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), + 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), register(gen_mod:get_module_proc(Host, ?PROCNAME), spawn(?MODULE, init, [MyHost, Host, Search])). - init(Host, ServerHost, Search) -> case Search of - false -> - loop(Host, ServerHost); - _ -> - ejabberd_router:register_route(Host), - loop(Host, ServerHost) + false -> loop(Host, ServerHost); + _ -> + ejabberd_router:register_route(Host), + loop(Host, ServerHost) end. loop(Host, ServerHost) -> receive - {route, From, To, Packet} -> - case catch do_route(ServerHost, From, To, Packet) of - {'EXIT', Reason} -> - ?ERROR_MSG("~p", [Reason]); - _ -> - ok - end, - loop(Host, ServerHost); - stop -> - ejabberd_router:unregister_route(Host), - ok; - _ -> - loop(Host, ServerHost) + {route, From, To, Packet} -> + case catch do_route(ServerHost, From, To, Packet) of + {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]); + _ -> ok + end, + loop(Host, ServerHost); + stop -> ejabberd_router:unregister_route(Host), ok; + _ -> loop(Host, ServerHost) end. stop(Host) -> - ejabberd_hooks:delete(remove_user, Host, - ?MODULE, remove_user, 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), + ejabberd_hooks:delete(remove_user, Host, ?MODULE, + remove_user, 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), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), Proc ! stop, {wait, Proc}. -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_DISCO_INFO, ?NS_VCARD | Features]}; - empty -> - {result, [?NS_DISCO_INFO, ?NS_VCARD]} - end; - _ -> - Acc - end. - -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"}]} - ]}]} + <<"">> -> + case Acc of + {result, Features} -> + {result, [?NS_DISCO_INFO, ?NS_VCARD | Features]}; + empty -> {result, [?NS_DISCO_INFO, ?NS_VCARD]} + end; + _ -> Acc end. +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 = + [#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, To, #iq{type = Type, sub_el = SubEl} = IQ) -> +process_sm_iq(From, To, + #iq{type = Type, sub_el = SubEl} = IQ) -> case Type of - set -> - #jid{user = User, lserver = LServer} = From, - case lists:member(LServer, ?MYHOSTS) of - true -> - set_vcard(User, LServer, SubEl), - IQ#iq{type = result, sub_el = []}; - false -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]} - end; - get -> - #jid{luser = LUser, lserver = LServer} = To, - case get_vcard(LUser, LServer) of - error -> - IQ#iq{type = error, - sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}; - Els -> - IQ#iq{type = result, sub_el = Els} - end + set -> + #jid{user = User, lserver = LServer} = From, + case lists:member(LServer, ?MYHOSTS) of + true -> + set_vcard(User, LServer, SubEl), + IQ#iq{type = result, sub_el = []}; + false -> + IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]} + end; + get -> + #jid{luser = LUser, lserver = LServer} = To, + case get_vcard(LUser, LServer) of + error -> + IQ#iq{type = error, + sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}; + Els -> IQ#iq{type = result, sub_el = Els} + end end. get_vcard(LUser, LServer) -> - get_vcard(LUser, LServer, gen_mod:db_type(LServer, ?MODULE)). + get_vcard(LUser, LServer, + gen_mod:db_type(LServer, ?MODULE)). get_vcard(LUser, LServer, mnesia) -> US = {LUser, LServer}, - F = fun() -> - mnesia:read({vcard, US}) - end, + F = fun () -> mnesia:read({vcard, US}) end, case mnesia:transaction(F) of - {atomic, Rs} -> - lists:map(fun(R) -> - R#vcard.vcard - end, Rs); - {aborted, _Reason} -> - error + {atomic, Rs} -> + lists:map(fun (R) -> R#vcard.vcard end, Rs); + {aborted, _Reason} -> error end; get_vcard(LUser, LServer, odbc) -> Username = ejabberd_odbc:escape(LUser), case catch odbc_queries:get_vcard(LServer, Username) of - {selected, ["vcard"], [{SVCARD}]} -> - case xml_stream:parse_element(SVCARD) of - {error, _Reason} -> - error; - VCARD -> - [VCARD] - end; - {selected, ["vcard"], []} -> - []; - _ -> - error + {selected, [<<"vcard">>], [[SVCARD]]} -> + case xml_stream:parse_element(SVCARD) of + {error, _Reason} -> error; + VCARD -> [VCARD] + end; + {selected, [<<"vcard">>], []} -> []; + _ -> error end. set_vcard(User, LServer, VCARD) -> - FN = xml:get_path_s(VCARD, [{elem, "FN"}, cdata]), - Family = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "FAMILY"}, cdata]), - Given = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "GIVEN"}, cdata]), - Middle = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "MIDDLE"}, cdata]), - Nickname = xml:get_path_s(VCARD, [{elem, "NICKNAME"}, cdata]), - BDay = xml:get_path_s(VCARD, [{elem, "BDAY"}, cdata]), - CTRY = xml:get_path_s(VCARD, [{elem, "ADR"}, {elem, "CTRY"}, cdata]), - Locality = xml:get_path_s(VCARD, [{elem, "ADR"}, {elem, "LOCALITY"},cdata]), - EMail1 = xml:get_path_s(VCARD, [{elem, "EMAIL"}, {elem, "USERID"},cdata]), - EMail2 = xml:get_path_s(VCARD, [{elem, "EMAIL"}, cdata]), - OrgName = xml:get_path_s(VCARD, [{elem, "ORG"}, {elem, "ORGNAME"}, cdata]), - OrgUnit = xml:get_path_s(VCARD, [{elem, "ORG"}, {elem, "ORGUNIT"}, cdata]), + FN = xml:get_path_s(VCARD, [{elem, <<"FN">>}, cdata]), + Family = xml:get_path_s(VCARD, + [{elem, <<"N">>}, {elem, <<"FAMILY">>}, cdata]), + Given = xml:get_path_s(VCARD, + [{elem, <<"N">>}, {elem, <<"GIVEN">>}, cdata]), + Middle = xml:get_path_s(VCARD, + [{elem, <<"N">>}, {elem, <<"MIDDLE">>}, cdata]), + Nickname = xml:get_path_s(VCARD, + [{elem, <<"NICKNAME">>}, cdata]), + BDay = xml:get_path_s(VCARD, + [{elem, <<"BDAY">>}, cdata]), + CTRY = xml:get_path_s(VCARD, + [{elem, <<"ADR">>}, {elem, <<"CTRY">>}, cdata]), + Locality = xml:get_path_s(VCARD, + [{elem, <<"ADR">>}, {elem, <<"LOCALITY">>}, + cdata]), + EMail1 = xml:get_path_s(VCARD, + [{elem, <<"EMAIL">>}, {elem, <<"USERID">>}, cdata]), + EMail2 = xml:get_path_s(VCARD, + [{elem, <<"EMAIL">>}, cdata]), + OrgName = xml:get_path_s(VCARD, + [{elem, <<"ORG">>}, {elem, <<"ORGNAME">>}, cdata]), + OrgUnit = xml:get_path_s(VCARD, + [{elem, <<"ORG">>}, {elem, <<"ORGUNIT">>}, cdata]), EMail = case EMail1 of - "" -> - EMail2; - _ -> - EMail1 + <<"">> -> EMail2; + _ -> EMail1 end, - - LUser = jlib:nodeprep(User), - LFN = string2lower(FN), - LFamily = string2lower(Family), - LGiven = string2lower(Given), - LMiddle = string2lower(Middle), + LUser = jlib:nodeprep(User), + LFN = string2lower(FN), + LFamily = string2lower(Family), + LGiven = string2lower(Given), + LMiddle = string2lower(Middle), LNickname = string2lower(Nickname), - LBDay = string2lower(BDay), - LCTRY = string2lower(CTRY), + LBDay = string2lower(BDay), + LCTRY = string2lower(CTRY), LLocality = string2lower(Locality), - LEMail = string2lower(EMail), - LOrgName = string2lower(OrgName), - LOrgUnit = string2lower(OrgUnit), - - if - (LUser == error) or - (LFN == error) or - (LFamily == error) or - (LGiven == error) or - (LMiddle == error) or - (LNickname == error) or - (LBDay == error) or - (LCTRY == error) or - (LLocality == error) or - (LEMail == error) or - (LOrgName == error) or - (LOrgUnit == error) -> - {error, badarg}; - true -> - case gen_mod:db_type(LServer, ?MODULE) of - mnesia -> - US = {LUser, LServer}, - F = fun() -> - mnesia:write(#vcard{us = US, vcard = VCARD}), - mnesia:write( - #vcard_search{us = US, - user = {User, LServer}, - luser = LUser, - fn = FN, lfn = LFN, - family = Family, lfamily = LFamily, - given = Given, lgiven = LGiven, - middle = Middle, lmiddle = LMiddle, - nickname = Nickname, lnickname = LNickname, - bday = BDay, lbday = LBDay, - ctry = CTRY, lctry = LCTRY, - locality = Locality, llocality = LLocality, - email = EMail, lemail = LEMail, - orgname = OrgName, lorgname = LOrgName, - orgunit = OrgUnit, lorgunit = LOrgUnit - }) - end, - mnesia:transaction(F); - odbc -> - Username = ejabberd_odbc:escape(User), - LUsername = ejabberd_odbc:escape(LUser), - SVCARD = ejabberd_odbc:escape( - xml:element_to_binary(VCARD)), - - SFN = ejabberd_odbc:escape(FN), - SLFN = ejabberd_odbc:escape(LFN), - SFamily = ejabberd_odbc:escape(Family), - SLFamily = ejabberd_odbc:escape(LFamily), - SGiven = ejabberd_odbc:escape(Given), - SLGiven = ejabberd_odbc:escape(LGiven), - SMiddle = ejabberd_odbc:escape(Middle), - SLMiddle = ejabberd_odbc:escape(LMiddle), - SNickname = ejabberd_odbc:escape(Nickname), - SLNickname = ejabberd_odbc:escape(LNickname), - SBDay = ejabberd_odbc:escape(BDay), - SLBDay = ejabberd_odbc:escape(LBDay), - SCTRY = ejabberd_odbc:escape(CTRY), - SLCTRY = ejabberd_odbc:escape(LCTRY), - SLocality = ejabberd_odbc:escape(Locality), - SLLocality = ejabberd_odbc:escape(LLocality), - SEMail = ejabberd_odbc:escape(EMail), - SLEMail = ejabberd_odbc:escape(LEMail), - SOrgName = ejabberd_odbc:escape(OrgName), - SLOrgName = ejabberd_odbc:escape(LOrgName), - SOrgUnit = ejabberd_odbc:escape(OrgUnit), - SLOrgUnit = ejabberd_odbc:escape(LOrgUnit), - - odbc_queries:set_vcard(LServer, LUsername, SBDay, SCTRY, SEMail, - SFN, SFamily, SGiven, SLBDay, SLCTRY, - SLEMail, SLFN, SLFamily, SLGiven, - SLLocality, SLMiddle, SLNickname, - SLOrgName, SLOrgUnit, SLocality, - SMiddle, SNickname, SOrgName, - SOrgUnit, SVCARD, Username) - end, - ejabberd_hooks:run(vcard_set, LServer, [LUser, LServer, VCARD]) + LEMail = string2lower(EMail), + LOrgName = string2lower(OrgName), + LOrgUnit = string2lower(OrgUnit), + if (LUser == error) -> + {error, badarg}; + true -> + case gen_mod:db_type(LServer, ?MODULE) of + mnesia -> + US = {LUser, LServer}, + F = fun () -> + mnesia:write(#vcard{us = US, vcard = VCARD}), + mnesia:write(#vcard_search{us = US, + user = {User, LServer}, + luser = LUser, fn = FN, + lfn = LFN, + family = Family, + lfamily = LFamily, + given = Given, + lgiven = LGiven, + middle = Middle, + lmiddle = LMiddle, + nickname = Nickname, + lnickname = LNickname, + bday = BDay, + lbday = LBDay, + ctry = CTRY, + lctry = LCTRY, + locality = Locality, + llocality = LLocality, + email = EMail, + lemail = LEMail, + orgname = OrgName, + lorgname = LOrgName, + orgunit = OrgUnit, + lorgunit = LOrgUnit}) + end, + mnesia:transaction(F); + odbc -> + Username = ejabberd_odbc:escape(User), + LUsername = ejabberd_odbc:escape(LUser), + SVCARD = + ejabberd_odbc:escape(xml:element_to_binary(VCARD)), + SFN = ejabberd_odbc:escape(FN), + SLFN = ejabberd_odbc:escape(LFN), + SFamily = ejabberd_odbc:escape(Family), + SLFamily = ejabberd_odbc:escape(LFamily), + SGiven = ejabberd_odbc:escape(Given), + SLGiven = ejabberd_odbc:escape(LGiven), + SMiddle = ejabberd_odbc:escape(Middle), + SLMiddle = ejabberd_odbc:escape(LMiddle), + SNickname = ejabberd_odbc:escape(Nickname), + SLNickname = ejabberd_odbc:escape(LNickname), + SBDay = ejabberd_odbc:escape(BDay), + SLBDay = ejabberd_odbc:escape(LBDay), + SCTRY = ejabberd_odbc:escape(CTRY), + SLCTRY = ejabberd_odbc:escape(LCTRY), + SLocality = ejabberd_odbc:escape(Locality), + SLLocality = ejabberd_odbc:escape(LLocality), + SEMail = ejabberd_odbc:escape(EMail), + SLEMail = ejabberd_odbc:escape(LEMail), + SOrgName = ejabberd_odbc:escape(OrgName), + SLOrgName = ejabberd_odbc:escape(LOrgName), + SOrgUnit = ejabberd_odbc:escape(OrgUnit), + SLOrgUnit = ejabberd_odbc:escape(LOrgUnit), + odbc_queries:set_vcard(LServer, LUsername, SBDay, SCTRY, + SEMail, SFN, SFamily, SGiven, SLBDay, + SLCTRY, SLEMail, SLFN, SLFamily, + SLGiven, SLLocality, SLMiddle, + SLNickname, SLOrgName, SLOrgUnit, + SLocality, SMiddle, SNickname, SOrgName, + SOrgUnit, SVCARD, Username) + end, + ejabberd_hooks:run(vcard_set, LServer, + [LUser, LServer, VCARD]) end. string2lower(String) -> case stringprep:tolower(String) of - Lower when is_list(Lower) -> Lower; - error -> string:to_lower(String) + Lower when is_binary(Lower) -> Lower; + error -> str:to_lower(String) end. -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), - [{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 the form to search " - "for any matching Jabber User " - "(Add * to the end of field to " - "match substring)")}]}, - ?TLFIELD("text-single", "User", "user"), - ?TLFIELD("text-single", "Full Name", "fn"), - ?TLFIELD("text-single", "Name", "first"), - ?TLFIELD("text-single", "Middle Name", "middle"), - ?TLFIELD("text-single", "Family Name", "last"), - ?TLFIELD("text-single", "Nickname", "nick"), - ?TLFIELD("text-single", "Birthday", "bday"), - ?TLFIELD("text-single", "Country", "ctry"), - ?TLFIELD("text-single", "City", "locality"), - ?TLFIELD("text-single", "Email", "email"), - ?TLFIELD("text-single", "Organization Name", "orgname"), - ?TLFIELD("text-single", "Organization Unit", "orgunit") - ]}]). - - - + [#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 the form to search for any matching " + "Jabber User (Add * to the end of field " + "to match substring)">>)}]}, + ?TLFIELD(<<"text-single">>, <<"User">>, <<"user">>), + ?TLFIELD(<<"text-single">>, <<"Full Name">>, <<"fn">>), + ?TLFIELD(<<"text-single">>, <<"Name">>, <<"first">>), + ?TLFIELD(<<"text-single">>, <<"Middle Name">>, + <<"middle">>), + ?TLFIELD(<<"text-single">>, <<"Family Name">>, + <<"last">>), + ?TLFIELD(<<"text-single">>, <<"Nickname">>, <<"nick">>), + ?TLFIELD(<<"text-single">>, <<"Birthday">>, <<"bday">>), + ?TLFIELD(<<"text-single">>, <<"Country">>, <<"ctry">>), + ?TLFIELD(<<"text-single">>, <<"City">>, <<"locality">>), + ?TLFIELD(<<"text-single">>, <<"Email">>, <<"email">>), + ?TLFIELD(<<"text-single">>, <<"Organization Name">>, + <<"orgname">>), + ?TLFIELD(<<"text-single">>, <<"Organization Unit">>, + <<"orgunit">>)]}]). do_route(ServerHost, From, To, Packet) -> #jid{user = User, resource = Resource} = To, - 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, ServerHost, XData) - }]}]}, - ejabberd_router:route( - To, From, jlib:iq_to_xml(ResIQ)) - end - end; - get -> - ResIQ = IQ#iq{type = result, - sub_el = [{xmlelement, - "query", - [{"xmlns", ?NS_SEARCH}], - ?FORM(To) - }]}, - 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_DISCO_INFO}], []}, - {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, + ServerHost, + XData)}]}]}, + ejabberd_router:route(To, From, + jlib:iq_to_xml(ResIQ)) + end + end; + get -> + ResIQ = IQ#iq{type = result, + sub_el = + [#xmlel{name = <<"query">>, + attrs = + [{<<"xmlns">>, + ?NS_SEARCH}], + children = ?FORM(To)}]}, + 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_DISCO_INFO}], + 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"}]}]. - -find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) -> + [#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">>}]}]. + +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). -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, ServerHost, Data) -> - [{xmlelement, "title", [], - [{xmlcdata, translate:translate(Lang, "Search Results for ") ++ - jlib:jid_to_string(JID)}]}, - {xmlelement, "reported", [], - [?TLFIELD("text-single", "Jabber ID", "jid"), - ?TLFIELD("text-single", "Full Name", "fn"), - ?TLFIELD("text-single", "Name", "first"), - ?TLFIELD("text-single", "Middle Name", "middle"), - ?TLFIELD("text-single", "Family Name", "last"), - ?TLFIELD("text-single", "Nickname", "nick"), - ?TLFIELD("text-single", "Birthday", "bday"), - ?TLFIELD("text-single", "Country", "ctry"), - ?TLFIELD("text-single", "City", "locality"), - ?TLFIELD("text-single", "Email", "email"), - ?TLFIELD("text-single", "Organization Name", "orgname"), - ?TLFIELD("text-single", "Organization Unit", "orgunit") - ]}] ++ lists:map(fun(R) -> record_to_item(ServerHost, R) end, - search(ServerHost, Data)). + [#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">>), + ?TLFIELD(<<"text-single">>, <<"Full Name">>, <<"fn">>), + ?TLFIELD(<<"text-single">>, <<"Name">>, <<"first">>), + ?TLFIELD(<<"text-single">>, <<"Middle Name">>, + <<"middle">>), + ?TLFIELD(<<"text-single">>, <<"Family Name">>, + <<"last">>), + ?TLFIELD(<<"text-single">>, <<"Nickname">>, <<"nick">>), + ?TLFIELD(<<"text-single">>, <<"Birthday">>, <<"bday">>), + ?TLFIELD(<<"text-single">>, <<"Country">>, <<"ctry">>), + ?TLFIELD(<<"text-single">>, <<"City">>, <<"locality">>), + ?TLFIELD(<<"text-single">>, <<"Email">>, <<"email">>), + ?TLFIELD(<<"text-single">>, <<"Organization Name">>, + <<"orgname">>), + ?TLFIELD(<<"text-single">>, <<"Organization Unit">>, + <<"orgunit">>)]}] + ++ + lists:map(fun (R) -> record_to_item(ServerHost, R) end, + search(ServerHost, Data)). -define(FIELD(Var, Val), - {xmlelement, "field", [{"var", Var}], - [{xmlelement, "value", [], - [{xmlcdata, Val}]}]}). - -record_to_item(LServer, {Username, FN, Family, Given, Middle, - Nickname, BDay, CTRY, Locality, - EMail, OrgName, OrgUnit}) -> - {xmlelement, "item", [], - [ - ?FIELD("jid", Username ++ "@" ++ LServer), - ?FIELD("fn", FN), - ?FIELD("last", Family), - ?FIELD("first", Given), - ?FIELD("middle", Middle), - ?FIELD("nick", Nickname), - ?FIELD("bday", BDay), - ?FIELD("ctry", CTRY), - ?FIELD("locality", Locality), - ?FIELD("email", EMail), - ?FIELD("orgname", OrgName), - ?FIELD("orgunit", OrgUnit) - ] - }; + #xmlel{name = <<"field">>, attrs = [{<<"var">>, Var}], + children = + [#xmlel{name = <<"value">>, attrs = [], + children = [{xmlcdata, Val}]}]}). + +record_to_item(LServer, + [Username, FN, Family, Given, Middle, Nickname, BDay, + CTRY, Locality, EMail, OrgName, OrgUnit]) -> + #xmlel{name = <<"item">>, attrs = [], + children = + [?FIELD(<<"jid">>, + <<Username/binary, "@", LServer/binary>>), + ?FIELD(<<"fn">>, FN), ?FIELD(<<"last">>, Family), + ?FIELD(<<"first">>, Given), + ?FIELD(<<"middle">>, Middle), + ?FIELD(<<"nick">>, Nickname), ?FIELD(<<"bday">>, BDay), + ?FIELD(<<"ctry">>, CTRY), + ?FIELD(<<"locality">>, Locality), + ?FIELD(<<"email">>, EMail), + ?FIELD(<<"orgname">>, OrgName), + ?FIELD(<<"orgunit">>, OrgUnit)]}; record_to_item(_LServer, #vcard_search{} = R) -> {User, Server} = R#vcard_search.user, - {xmlelement, "item", [], - [ - ?FIELD("jid", User ++ "@" ++ Server), - ?FIELD("fn", R#vcard_search.fn), - ?FIELD("last", R#vcard_search.family), - ?FIELD("first", R#vcard_search.given), - ?FIELD("middle", R#vcard_search.middle), - ?FIELD("nick", R#vcard_search.nickname), - ?FIELD("bday", R#vcard_search.bday), - ?FIELD("ctry", R#vcard_search.ctry), - ?FIELD("locality", R#vcard_search.locality), - ?FIELD("email", R#vcard_search.email), - ?FIELD("orgname", R#vcard_search.orgname), - ?FIELD("orgunit", R#vcard_search.orgunit) - ] - }. - + #xmlel{name = <<"item">>, attrs = [], + children = + [?FIELD(<<"jid">>, <<User/binary, "@", Server/binary>>), + ?FIELD(<<"fn">>, (R#vcard_search.fn)), + ?FIELD(<<"last">>, (R#vcard_search.family)), + ?FIELD(<<"first">>, (R#vcard_search.given)), + ?FIELD(<<"middle">>, (R#vcard_search.middle)), + ?FIELD(<<"nick">>, (R#vcard_search.nickname)), + ?FIELD(<<"bday">>, (R#vcard_search.bday)), + ?FIELD(<<"ctry">>, (R#vcard_search.ctry)), + ?FIELD(<<"locality">>, (R#vcard_search.locality)), + ?FIELD(<<"email">>, (R#vcard_search.email)), + ?FIELD(<<"orgname">>, (R#vcard_search.orgname)), + ?FIELD(<<"orgunit">>, (R#vcard_search.orgunit))]}. search(LServer, Data) -> - DBType = gen_mod:db_type(LServer, ?MODULE), + DBType = gen_mod:db_type(LServer, ?MODULE), MatchSpec = make_matchspec(LServer, Data, DBType), - AllowReturnAll = gen_mod:get_module_opt(LServer, ?MODULE, - allow_return_all, false), + AllowReturnAll = gen_mod:get_module_opt(LServer, ?MODULE, allow_return_all, + fun(B) when is_boolean(B) -> B end, + false), search(LServer, MatchSpec, AllowReturnAll, DBType). search(LServer, MatchSpec, AllowReturnAll, mnesia) -> - if - (MatchSpec == #vcard_search{_ = '_'}) and (not AllowReturnAll) -> - []; - true -> - case catch mnesia:dirty_select(vcard_search, - [{MatchSpec, [], ['$_']}]) of - {'EXIT', Reason} -> - ?ERROR_MSG("~p", [Reason]), - []; - Rs -> - case gen_mod:get_module_opt(LServer, ?MODULE, - matches, ?JUD_MATCHES) of - infinity -> - Rs; - Val when is_integer(Val) and (Val > 0) -> - lists:sublist(Rs, Val); - Val -> - ?ERROR_MSG("Illegal option value ~p. " - "Default value ~p substituted.", - [{matches, Val}, ?JUD_MATCHES]), - lists:sublist(Rs, ?JUD_MATCHES) - end - end + if (MatchSpec == #vcard_search{_ = '_'}) and + not AllowReturnAll -> + []; + true -> + case catch mnesia:dirty_select(vcard_search, + [{MatchSpec, [], ['$_']}]) + of + {'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]), []; + Rs -> + case gen_mod:get_module_opt(LServer, ?MODULE, matches, + fun(infinity) -> infinity; + (I) when is_integer(I), + I>0 -> + I + end, ?JUD_MATCHES) of + infinity -> + Rs; + Val -> + lists:sublist(Rs, Val) + end + end end; search(LServer, MatchSpec, AllowReturnAll, odbc) -> - if - (MatchSpec == "") and (not AllowReturnAll) -> - []; - true -> - Limit = case gen_mod:get_module_opt(LServer, ?MODULE, - matches, ?JUD_MATCHES) of - infinity -> - ""; - Val when is_integer(Val) and (Val > 0) -> - [" LIMIT ", integer_to_list(Val)]; - Val -> - ?ERROR_MSG("Illegal option value ~p. " - "Default value ~p substituted.", - [{matches, Val}, ?JUD_MATCHES]), - [" LIMIT ", integer_to_list(?JUD_MATCHES)] - end, - case catch ejabberd_odbc:sql_query( - LServer, - ["select username, fn, family, given, middle, " - " nickname, bday, ctry, locality, " - " email, orgname, orgunit from vcard_search ", - MatchSpec, Limit, ";"]) of - {selected, ["username", "fn", "family", "given", "middle", - "nickname", "bday", "ctry", "locality", - "email", "orgname", "orgunit"], - Rs} when is_list(Rs) -> - Rs; - Error -> - ?ERROR_MSG("~p", [Error]), - [] - end + if (MatchSpec == <<"">>) and not AllowReturnAll -> []; + true -> + Limit = case gen_mod:get_module_opt(LServer, ?MODULE, matches, + fun(infinity) -> infinity; + (I) when is_integer(I), + I>0 -> + I + end, ?JUD_MATCHES) of + infinity -> + <<"">>; + Val -> + [<<" LIMIT ">>, + jlib:integer_to_binary(Val)] + end, + case catch ejabberd_odbc:sql_query(LServer, + [<<"select username, fn, family, given, " + "middle, nickname, bday, ctry, " + "locality, email, orgname, orgunit " + "from vcard_search ">>, + MatchSpec, Limit, <<";">>]) + of + {selected, + [<<"username">>, <<"fn">>, <<"family">>, <<"given">>, + <<"middle">>, <<"nickname">>, <<"bday">>, <<"ctry">>, + <<"locality">>, <<"email">>, <<"orgname">>, + <<"orgunit">>], + Rs} + when is_list(Rs) -> + Rs; + Error -> ?ERROR_MSG("~p", [Error]), [] + end end. make_matchspec(LServer, Data, mnesia) -> @@ -670,203 +694,197 @@ make_matchspec(LServer, Data, mnesia) -> Match = filter_fields(Data, GlobMatch, LServer, mnesia), Match; make_matchspec(LServer, Data, odbc) -> - filter_fields(Data, "", LServer, odbc). + filter_fields(Data, <<"">>, LServer, odbc). -filter_fields([], Match, _LServer, mnesia) -> - Match; +filter_fields([], Match, _LServer, mnesia) -> Match; filter_fields([], Match, _LServer, odbc) -> case Match of - "" -> - ""; - _ -> - [" where ", Match] + <<"">> -> <<"">>; + _ -> [<<" where ">>, Match] end; -filter_fields([{SVar, [Val]} | Ds], Match, LServer, mnesia) - when is_list(Val) and (Val /= "") -> +filter_fields([{SVar, [Val]} | Ds], Match, LServer, + mnesia) + when is_binary(Val) and (Val /= <<"">>) -> LVal = string2lower(Val), NewMatch = case SVar of - "user" -> - case gen_mod:get_module_opt(LServer, ?MODULE, - search_all_hosts, true) of - true -> - Match#vcard_search{luser = make_val(LVal)}; - false -> - Host = find_my_host(LServer), - Match#vcard_search{us = {make_val(LVal), Host}} - end; - "fn" -> Match#vcard_search{lfn = make_val(LVal)}; - "last" -> Match#vcard_search{lfamily = make_val(LVal)}; - "first" -> Match#vcard_search{lgiven = make_val(LVal)}; - "middle" -> Match#vcard_search{lmiddle = make_val(LVal)}; - "nick" -> Match#vcard_search{lnickname = make_val(LVal)}; - "bday" -> Match#vcard_search{lbday = make_val(LVal)}; - "ctry" -> Match#vcard_search{lctry = make_val(LVal)}; - "locality" -> Match#vcard_search{llocality = make_val(LVal)}; - "email" -> Match#vcard_search{lemail = make_val(LVal)}; - "orgname" -> Match#vcard_search{lorgname = make_val(LVal)}; - "orgunit" -> Match#vcard_search{lorgunit = make_val(LVal)}; - _ -> Match + <<"user">> -> + case gen_mod:get_module_opt(LServer, ?MODULE, + search_all_hosts, + fun(B) when is_boolean(B) -> + B + end, true) + of + true -> Match#vcard_search{luser = make_val(LVal)}; + false -> + Host = find_my_host(LServer), + Match#vcard_search{us = {make_val(LVal), Host}} + end; + <<"fn">> -> Match#vcard_search{lfn = make_val(LVal)}; + <<"last">> -> + Match#vcard_search{lfamily = make_val(LVal)}; + <<"first">> -> + Match#vcard_search{lgiven = make_val(LVal)}; + <<"middle">> -> + Match#vcard_search{lmiddle = make_val(LVal)}; + <<"nick">> -> + Match#vcard_search{lnickname = make_val(LVal)}; + <<"bday">> -> + Match#vcard_search{lbday = make_val(LVal)}; + <<"ctry">> -> + Match#vcard_search{lctry = make_val(LVal)}; + <<"locality">> -> + Match#vcard_search{llocality = make_val(LVal)}; + <<"email">> -> + Match#vcard_search{lemail = make_val(LVal)}; + <<"orgname">> -> + Match#vcard_search{lorgname = make_val(LVal)}; + <<"orgunit">> -> + Match#vcard_search{lorgunit = make_val(LVal)}; + _ -> Match end, filter_fields(Ds, NewMatch, LServer, mnesia); -filter_fields([{SVar, [Val]} | Ds], Match, LServer, odbc) - when is_list(Val) and (Val /= "") -> +filter_fields([{SVar, [Val]} | Ds], Match, LServer, + odbc) + when is_binary(Val) and (Val /= <<"">>) -> LVal = string2lower(Val), NewMatch = case SVar of - "user" -> make_val(Match, "lusername", LVal); - "fn" -> make_val(Match, "lfn", LVal); - "last" -> make_val(Match, "lfamily", LVal); - "first" -> make_val(Match, "lgiven", LVal); - "middle" -> make_val(Match, "lmiddle", LVal); - "nick" -> make_val(Match, "lnickname", LVal); - "bday" -> make_val(Match, "lbday", LVal); - "ctry" -> make_val(Match, "lctry", LVal); - "locality" -> make_val(Match, "llocality", LVal); - "email" -> make_val(Match, "lemail", LVal); - "orgname" -> make_val(Match, "lorgname", LVal); - "orgunit" -> make_val(Match, "lorgunit", LVal); - _ -> Match + <<"user">> -> make_val(Match, <<"lusername">>, LVal); + <<"fn">> -> make_val(Match, <<"lfn">>, LVal); + <<"last">> -> make_val(Match, <<"lfamily">>, LVal); + <<"first">> -> make_val(Match, <<"lgiven">>, LVal); + <<"middle">> -> make_val(Match, <<"lmiddle">>, LVal); + <<"nick">> -> make_val(Match, <<"lnickname">>, LVal); + <<"bday">> -> make_val(Match, <<"lbday">>, LVal); + <<"ctry">> -> make_val(Match, <<"lctry">>, LVal); + <<"locality">> -> + make_val(Match, <<"llocality">>, LVal); + <<"email">> -> make_val(Match, <<"lemail">>, LVal); + <<"orgname">> -> make_val(Match, <<"lorgname">>, LVal); + <<"orgunit">> -> make_val(Match, <<"lorgunit">>, LVal); + _ -> Match end, filter_fields(Ds, NewMatch, LServer, odbc); filter_fields([_ | Ds], Match, LServer, DBType) -> filter_fields(Ds, Match, LServer, DBType). make_val(Match, Field, Val) -> - Condition = - case lists:suffix("*", Val) of - true -> - Val1 = lists:sublist(Val, length(Val) - 1), - SVal = ejabberd_odbc:escape_like(Val1) ++ "%", - [Field, " LIKE '", SVal, "'"]; - _ -> - SVal = ejabberd_odbc:escape(Val), - [Field, " = '", SVal, "'"] - end, + Condition = case str:suffix(<<"*">>, Val) of + true -> + Val1 = str:substr(Val, 1, byte_size(Val) - 1), + SVal = <<(ejabberd_odbc:escape_like(Val1))/binary, + "%">>, + [Field, <<" LIKE '">>, SVal, <<"'">>]; + _ -> + SVal = ejabberd_odbc:escape(Val), + [Field, <<" = '">>, SVal, <<"'">>] + end, case Match of - "" -> - Condition; - _ -> - [Match, " and ", Condition] + <<"">> -> Condition; + _ -> [Match, <<" and ">>, Condition] end. make_val(Val) -> - case lists:suffix("*", Val) of - true -> - lists:sublist(Val, length(Val) - 1) ++ '_'; - _ -> - Val + case str:suffix(<<"*">>, Val) of + true -> [str:substr(Val, 1, byte_size(Val) - 1)] ++ '_'; + _ -> Val end. find_my_host(LServer) -> - Parts = string:tokens(LServer, "."), + Parts = str:tokens(LServer, <<".">>), find_my_host(Parts, ?MYHOSTS). -find_my_host([], _Hosts) -> - ?MYNAME; +find_my_host([], _Hosts) -> ?MYNAME; find_my_host([_ | Tail] = Parts, Hosts) -> Domain = parts_to_string(Parts), case lists:member(Domain, Hosts) of - true -> - Domain; - false -> - find_my_host(Tail, Hosts) + true -> Domain; + false -> find_my_host(Tail, Hosts) end. parts_to_string(Parts) -> - string:strip(lists:flatten(lists:map(fun(S) -> [S, $.] end, Parts)), - right, $.). - - + str:strip(list_to_binary( + lists:map(fun (S) -> <<S/binary, $.>> end, Parts)), + right, $.). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% set_vcard_t(R, _) -> US = R#vcard.us, - User = US, + User = US, VCARD = R#vcard.vcard, - - FN = xml:get_path_s(VCARD, [{elem, "FN"}, cdata]), - Family = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "FAMILY"}, cdata]), - Given = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "GIVEN"}, cdata]), - Middle = xml:get_path_s(VCARD, [{elem, "N"}, {elem, "MIDDLE"}, cdata]), - Nickname = xml:get_path_s(VCARD, [{elem, "NICKNAME"}, cdata]), - BDay = xml:get_path_s(VCARD, [{elem, "BDAY"}, cdata]), - CTRY = xml:get_path_s(VCARD, [{elem, "ADR"}, {elem, "CTRY"}, cdata]), - Locality = xml:get_path_s(VCARD, [{elem, "ADR"}, {elem, "LOCALITY"},cdata]), - EMail = xml:get_path_s(VCARD, [{elem, "EMAIL"}, cdata]), - OrgName = xml:get_path_s(VCARD, [{elem, "ORG"}, {elem, "ORGNAME"}, cdata]), - OrgUnit = xml:get_path_s(VCARD, [{elem, "ORG"}, {elem, "ORGUNIT"}, cdata]), - + FN = xml:get_path_s(VCARD, [{elem, <<"FN">>}, cdata]), + Family = xml:get_path_s(VCARD, + [{elem, <<"N">>}, {elem, <<"FAMILY">>}, cdata]), + Given = xml:get_path_s(VCARD, + [{elem, <<"N">>}, {elem, <<"GIVEN">>}, cdata]), + Middle = xml:get_path_s(VCARD, + [{elem, <<"N">>}, {elem, <<"MIDDLE">>}, cdata]), + Nickname = xml:get_path_s(VCARD, + [{elem, <<"NICKNAME">>}, cdata]), + BDay = xml:get_path_s(VCARD, + [{elem, <<"BDAY">>}, cdata]), + CTRY = xml:get_path_s(VCARD, + [{elem, <<"ADR">>}, {elem, <<"CTRY">>}, cdata]), + Locality = xml:get_path_s(VCARD, + [{elem, <<"ADR">>}, {elem, <<"LOCALITY">>}, + cdata]), + EMail = xml:get_path_s(VCARD, + [{elem, <<"EMAIL">>}, cdata]), + OrgName = xml:get_path_s(VCARD, + [{elem, <<"ORG">>}, {elem, <<"ORGNAME">>}, cdata]), + OrgUnit = xml:get_path_s(VCARD, + [{elem, <<"ORG">>}, {elem, <<"ORGUNIT">>}, cdata]), {LUser, _LServer} = US, - LFN = string2lower(FN), - LFamily = string2lower(Family), - LGiven = string2lower(Given), - LMiddle = string2lower(Middle), + LFN = string2lower(FN), + LFamily = string2lower(Family), + LGiven = string2lower(Given), + LMiddle = string2lower(Middle), LNickname = string2lower(Nickname), - LBDay = string2lower(BDay), - LCTRY = string2lower(CTRY), + LBDay = string2lower(BDay), + LCTRY = string2lower(CTRY), LLocality = string2lower(Locality), - LEMail = string2lower(EMail), - LOrgName = string2lower(OrgName), - LOrgUnit = string2lower(OrgUnit), - - if - (LUser == error) or - (LFN == error) or - (LFamily == error) or - (LGiven == error) or - (LMiddle == error) or - (LNickname == error) or - (LBDay == error) or - (LCTRY == error) or - (LLocality == error) or - (LEMail == error) or - (LOrgName == error) or - (LOrgUnit == error) -> - {error, badarg}; - true -> - mnesia:write( - #vcard_search{us = US, - user = User, luser = LUser, - fn = FN, lfn = LFN, - family = Family, lfamily = LFamily, - given = Given, lgiven = LGiven, - middle = Middle, lmiddle = LMiddle, - nickname = Nickname, lnickname = LNickname, - bday = BDay, lbday = LBDay, - ctry = CTRY, lctry = LCTRY, - locality = Locality, llocality = LLocality, - email = EMail, lemail = LEMail, - orgname = OrgName, lorgname = LOrgName, - orgunit = OrgUnit, lorgunit = LOrgUnit - }) - end. - + LEMail = string2lower(EMail), + LOrgName = string2lower(OrgName), + LOrgUnit = string2lower(OrgUnit), + mnesia:write(#vcard_search{us = US, user = User, + luser = LUser, fn = FN, lfn = LFN, + family = Family, lfamily = LFamily, + given = Given, lgiven = LGiven, + middle = Middle, lmiddle = LMiddle, + nickname = Nickname, + lnickname = LNickname, bday = BDay, + lbday = LBDay, ctry = CTRY, lctry = LCTRY, + locality = Locality, + llocality = LLocality, email = EMail, + lemail = LEMail, orgname = OrgName, + lorgname = LOrgName, orgunit = OrgUnit, + lorgunit = LOrgUnit}). reindex_vcards() -> - F = fun() -> - mnesia:foldl(fun set_vcard_t/2, [], vcard) + F = fun () -> mnesia:foldl(fun set_vcard_t/2, [], vcard) end, mnesia:transaction(F). - remove_user(User, Server) -> LUser = jlib:nodeprep(User), LServer = jlib:nameprep(Server), - remove_user(LUser, LServer, gen_mod:db_type(LServer, ?MODULE)). + remove_user(LUser, LServer, + gen_mod:db_type(LServer, ?MODULE)). remove_user(LUser, LServer, mnesia) -> US = {LUser, LServer}, - F = fun() -> + F = fun () -> mnesia:delete({vcard, US}), mnesia:delete({vcard_search, US}) end, mnesia:transaction(F); remove_user(LUser, LServer, odbc) -> Username = ejabberd_odbc:escape(LUser), - ejabberd_odbc:sql_transaction( - LServer, - [["delete from vcard where username='", Username, "';"], - ["delete from vcard_search where lusername='", Username, "';"]]). + ejabberd_odbc:sql_transaction(LServer, + [[<<"delete from vcard where username='">>, + Username, <<"';">>], + [<<"delete from vcard_search where lusername='">>, + Username, <<"';">>]]). update_tables() -> update_vcard_table(), @@ -875,141 +893,115 @@ update_tables() -> update_vcard_table() -> Fields = record_info(fields, vcard), case mnesia:table_info(vcard, attributes) of - Fields -> - ok; - [user, vcard] -> - ?INFO_MSG("Converting vcard table from " - "{user, vcard} format", []), - Host = ?MYNAME, - {atomic, ok} = mnesia:create_table( - mod_vcard_tmp_table, - [{disc_only_copies, [node()]}, - {type, bag}, - {local_content, true}, - {record_name, vcard}, - {attributes, record_info(fields, vcard)}]), - mnesia:transform_table(vcard, ignore, Fields), - F1 = fun() -> - mnesia:write_lock_table(mod_vcard_tmp_table), - mnesia:foldl( - fun(#vcard{us = U} = R, _) -> - mnesia:dirty_write( - mod_vcard_tmp_table, - R#vcard{us = {U, Host}}) - end, ok, vcard) - end, - mnesia:transaction(F1), - mnesia:clear_table(vcard), - F2 = fun() -> - mnesia:write_lock_table(vcard), - mnesia:foldl( - fun(R, _) -> - mnesia:dirty_write(R) - end, ok, mod_vcard_tmp_table) - end, - mnesia:transaction(F2), - mnesia:delete_table(mod_vcard_tmp_table); - _ -> - ?INFO_MSG("Recreating vcard table", []), - mnesia:transform_table(vcard, ignore, Fields) + Fields -> + ejabberd_config:convert_table_to_binary( + vcard, Fields, set, + fun(#vcard{us = {U, _}}) -> U end, + fun(#vcard{us = {U, S}, vcard = El} = R) -> + R#vcard{us = {iolist_to_binary(U), + iolist_to_binary(S)}, + vcard = xml:to_xmlel(El)} + end); + _ -> + ?INFO_MSG("Recreating vcard table", []), + mnesia:transform_table(vcard, ignore, Fields) end. - update_vcard_search_table() -> Fields = record_info(fields, vcard_search), case mnesia:table_info(vcard_search, attributes) of - Fields -> - ok; - [user, luser, - fn, lfn, - family, lfamily, - given, lgiven, - middle, lmiddle, - nickname, lnickname, - bday, lbday, - ctry, lctry, - locality, llocality, - email, lemail, - orgname, lorgname, - orgunit, lorgunit] -> - ?INFO_MSG("Converting vcard_search table from " - "{user, luser, fn, lfn, family, lfamily, given, lgiven, middle, lmiddle, nickname, lnickname, bday, lbday, ctry, lctry, locality, llocality, email, lemail, orgname, lorgname, orgunit, lorgunit} format", []), - Host = ?MYNAME, - {atomic, ok} = mnesia:create_table( - mod_vcard_tmp_table, - [{disc_only_copies, [node()]}, - {type, bag}, - {local_content, true}, - {record_name, vcard_search}, - {attributes, record_info(fields, vcard_search)}]), - F1 = fun() -> - mnesia:write_lock_table(mod_vcard_tmp_table), - mnesia:foldl( - fun({vcard_search, - User, LUser, - FN, LFN, - Family, LFamily, - Given, LGiven, - Middle, LMiddle, - Nickname, LNickname, - BDay, LBDay, - CTRY, LCTRY, - Locality, LLocality, - EMail, LEMail, - OrgName, LOrgName, - OrgUnit, LOrgUnit - }, _) -> - mnesia:dirty_write( - mod_vcard_tmp_table, - #vcard_search{ - us = {LUser, Host}, - user = {User, Host}, - luser = LUser, - fn = FN, lfn = LFN, - family = Family, lfamily = LFamily, - given = Given, lgiven = LGiven, - middle = Middle, lmiddle = LMiddle, - nickname = Nickname, lnickname = LNickname, - bday = BDay, lbday = LBDay, - ctry = CTRY, lctry = LCTRY, - locality = Locality, llocality = LLocality, - email = EMail, lemail = LEMail, - orgname = OrgName, lorgname = LOrgName, - orgunit = OrgUnit, lorgunit = LOrgUnit - }) - end, ok, vcard_search) - end, - mnesia:transaction(F1), - lists:foreach(fun(I) -> - mnesia:del_table_index( - vcard_search, - element(I, {vcard_search, - user, luser, - fn, lfn, - family, lfamily, - given, lgiven, - middle, lmiddle, - nickname, lnickname, - bday, lbday, - ctry, lctry, - locality, llocality, - email, lemail, - orgname, lorgname, - orgunit, lorgunit})) - end, mnesia:table_info(vcard_search, index)), - mnesia:clear_table(vcard_search), - mnesia:transform_table(vcard_search, ignore, Fields), - F2 = fun() -> - mnesia:write_lock_table(vcard_search), - mnesia:foldl( - fun(R, _) -> - mnesia:dirty_write(R) - end, ok, mod_vcard_tmp_table) - end, - mnesia:transaction(F2), - mnesia:delete_table(mod_vcard_tmp_table); - _ -> - ?INFO_MSG("Recreating vcard_search table", []), - mnesia:transform_table(vcard_search, ignore, Fields) + Fields -> + ejabberd_config:convert_table_to_binary( + vcard_search, Fields, set, + fun(#vcard_search{us = {U, _}}) -> U end, + fun(#vcard_search{} = VS) -> + [vcard_search | L] = tuple_to_list(VS), + NewL = lists:map( + fun({U, S}) -> + {iolist_to_binary(U), + iolist_to_binary(S)}; + (Str) -> + iolist_to_binary(Str) + end, L), + list_to_tuple([vcard_search | NewL]) + end); + _ -> + ?INFO_MSG("Recreating vcard_search table", []), + mnesia:transform_table(vcard_search, ignore, Fields) end. +export(_Server) -> + [{vcard, + fun(Host, #vcard{us = {LUser, LServer}, vcard = VCARD}) + when LServer == Host -> + Username = ejabberd_odbc:escape(LUser), + SVCARD = + ejabberd_odbc:escape(xml:element_to_binary(VCARD)), + [[<<"delete from vcard where username='">>, Username, <<"';">>], + [<<"insert into vcard(username, vcard) values ('">>, + Username, <<"', '">>, SVCARD, <<"');">>]]; + (_Host, _R) -> + [] + end}, + {vcard_search, + fun(Host, #vcard_search{user = {User, LServer}, luser = LUser, + fn = FN, lfn = LFN, family = Family, + lfamily = LFamily, given = Given, + lgiven = LGiven, middle = Middle, + lmiddle = LMiddle, nickname = Nickname, + lnickname = LNickname, bday = BDay, + lbday = LBDay, ctry = CTRY, lctry = LCTRY, + locality = Locality, llocality = LLocality, + email = EMail, lemail = LEMail, + orgname = OrgName, lorgname = LOrgName, + orgunit = OrgUnit, lorgunit = LOrgUnit}) + when LServer == Host -> + Username = ejabberd_odbc:escape(User), + LUsername = ejabberd_odbc:escape(LUser), + SFN = ejabberd_odbc:escape(FN), + SLFN = ejabberd_odbc:escape(LFN), + SFamily = ejabberd_odbc:escape(Family), + SLFamily = ejabberd_odbc:escape(LFamily), + SGiven = ejabberd_odbc:escape(Given), + SLGiven = ejabberd_odbc:escape(LGiven), + SMiddle = ejabberd_odbc:escape(Middle), + SLMiddle = ejabberd_odbc:escape(LMiddle), + SNickname = ejabberd_odbc:escape(Nickname), + SLNickname = ejabberd_odbc:escape(LNickname), + SBDay = ejabberd_odbc:escape(BDay), + SLBDay = ejabberd_odbc:escape(LBDay), + SCTRY = ejabberd_odbc:escape(CTRY), + SLCTRY = ejabberd_odbc:escape(LCTRY), + SLocality = ejabberd_odbc:escape(Locality), + SLLocality = ejabberd_odbc:escape(LLocality), + SEMail = ejabberd_odbc:escape(EMail), + SLEMail = ejabberd_odbc:escape(LEMail), + SOrgName = ejabberd_odbc:escape(OrgName), + SLOrgName = ejabberd_odbc:escape(LOrgName), + SOrgUnit = ejabberd_odbc:escape(OrgUnit), + SLOrgUnit = ejabberd_odbc:escape(LOrgUnit), + [[<<"delete from vcard_search where lusername='">>, + LUsername, <<"';">>], + [<<"insert into vcard_search( username, " + "lusername, fn, lfn, family, lfamily, " + " given, lgiven, middle, lmiddle, " + "nickname, lnickname, bday, lbday, " + "ctry, lctry, locality, llocality, " + " email, lemail, orgname, lorgname, " + "orgunit, lorgunit)values (">>, + <<" '">>, Username, <<"', '">>, LUsername, + <<"', '">>, SFN, <<"', '">>, SLFN, + <<"', '">>, SFamily, <<"', '">>, SLFamily, + <<"', '">>, SGiven, <<"', '">>, SLGiven, + <<"', '">>, SMiddle, <<"', '">>, SLMiddle, + <<"', '">>, SNickname, <<"', '">>, SLNickname, + <<"', '">>, SBDay, <<"', '">>, SLBDay, + <<"', '">>, SCTRY, <<"', '">>, SLCTRY, + <<"', '">>, SLocality, <<"', '">>, SLLocality, + <<"', '">>, SEMail, <<"', '">>, SLEMail, + <<"', '">>, SOrgName, <<"', '">>, SLOrgName, + <<"', '">>, SOrgUnit, <<"', '">>, SLOrgUnit, + <<"');">>]]; + (_Host, _R) -> + [] + end}]. |