aboutsummaryrefslogtreecommitdiff
path: root/src/mod_vcard.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_vcard.erl')
-rw-r--r--src/mod_vcard.erl762
1 files changed, 385 insertions, 377 deletions
diff --git a/src/mod_vcard.erl b/src/mod_vcard.erl
index ee109e598..4aedf18d2 100644
--- a/src/mod_vcard.erl
+++ b/src/mod_vcard.erl
@@ -36,8 +36,9 @@
reindex_vcards/0,
remove_user/2]).
+-include_lib("exmpp/include/exmpp.hrl").
+
-include("ejabberd.hrl").
--include("jlib.hrl").
-define(JUD_MATCHES, 30).
@@ -61,6 +62,7 @@
-define(PROCNAME, ejabberd_mod_vcard).
start(Host, Opts) ->
+ HostB = list_to_binary(Host),
mnesia:create_table(vcard, [{disc_only_copies, [node()]},
{attributes, record_info(fields, vcard)}]),
mnesia:create_table(vcard_search,
@@ -80,14 +82,14 @@ start(Host, Opts) ->
mnesia:add_table_index(vcard_search, lorgname),
mnesia:add_table_index(vcard_search, lorgunit),
- ejabberd_hooks:add(remove_user, Host,
+ ejabberd_hooks:add(remove_user, HostB,
?MODULE, remove_user, 50),
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
- gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD,
+ gen_iq_handler:add_iq_handler(ejabberd_local, HostB, ?NS_VCARD,
?MODULE, process_local_iq, IQDisc),
- gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD,
+ gen_iq_handler:add_iq_handler(ejabberd_sm, HostB, ?NS_VCARD,
?MODULE, process_sm_iq, IQDisc),
- ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
+ ejabberd_hooks:add(disco_sm_features, HostB, ?MODULE, get_sm_features, 50),
MyHost = gen_mod:get_opt_host(Host, Opts, "vjud.@HOST@"),
Search = gen_mod:get_opt(search, Opts, true),
register(gen_mod:get_module_proc(Host, ?PROCNAME),
@@ -121,11 +123,14 @@ loop(Host, ServerHost) ->
end.
stop(Host) ->
- ejabberd_hooks:delete(remove_user, Host,
+ HostB = list_to_binary(Host),
+ ejabberd_hooks:delete(remove_user, HostB,
?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),
+ gen_iq_handler:remove_iq_handler(ejabberd_local, HostB,
+ ?NS_VCARD),
+ gen_iq_handler:remove_iq_handler(ejabberd_sm, HostB,
+ ?NS_VCARD),
+ ejabberd_hooks:delete(disco_sm_features, HostB, ?MODULE, get_sm_features, 50),
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
Proc ! stop,
{wait, Proc}.
@@ -138,79 +143,88 @@ get_sm_features(Acc, _From, _To, Node, _Lang) ->
[] ->
case Acc of
{result, Features} ->
- {result, [?NS_DISCO_INFO, ?NS_VCARD | Features]};
+ {result, [?NS_DISCO_INFO_s, ?NS_VCARD_s | Features]};
empty ->
- {result, [?NS_DISCO_INFO, ?NS_VCARD]}
+ {result, [?NS_DISCO_INFO_s, ?NS_VCARD_s]}
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-2009 ProcessOne"}]},
- {xmlelement, "BDAY", [],
- [{xmlcdata, "2002-11-16"}]}
- ]}]}
- end.
-
-
-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,
- US = {LUser, LServer},
- F = fun() ->
- mnesia:read({vcard, US})
- end,
- Els = case mnesia:transaction(F) of
- {atomic, Rs} ->
- lists:map(fun(R) ->
- R#vcard.vcard
- end, Rs);
- {aborted, _Reason} ->
- []
- end,
- IQ#iq{type = result, sub_el = Els}
+process_local_iq(_From, _To, #iq{type = get, lang = Lang} = IQ_Rec) ->
+ Result = #xmlel{ns = ?NS_VCARD, name = 'vCard', children = [
+ exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'FN'},
+ "ejabberd"),
+ exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'URL'},
+ ?EJABBERD_URI),
+ exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'DESC'},
+ translate:translate(Lang, "Erlang Jabber Server") ++
+ "\nCopyright (c) 2002-2009 ProcessOne"),
+ exmpp_xml:set_cdata(#xmlel{ns = ?NS_VCARD, name = 'BDAY'},
+ "2002-11-16")
+ ]},
+ exmpp_iq:result(IQ_Rec, Result);
+process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) ->
+ exmpp_iq:error(IQ_Rec, 'not-allowed').
+
+
+process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) ->
+ LUser = exmpp_jid:prep_node_as_list(To),
+ LServer = exmpp_jid:prep_domain_as_list(To),
+ US = {LUser, LServer},
+ F = fun() ->
+ mnesia:read({vcard, US})
+ end,
+ Els = case mnesia:transaction(F) of
+ {atomic, Rs} ->
+ lists:map(fun(R) ->
+ R#vcard.vcard
+ end, Rs);
+ {aborted, _Reason} ->
+ []
+ end,
+ case Els of
+ [VCard | _] ->
+ exmpp_iq:result(IQ_Rec, VCard);
+ _ ->
+ exmpp_iq:result(IQ_Rec)
+ end;
+process_sm_iq(From, _To, #iq{type = set, payload = Request} = IQ_Rec) ->
+ User = exmpp_jid:node_as_list(From),
+ LServer = exmpp_jid:prep_domain_as_list(From),
+ case lists:member(LServer, ?MYHOSTS) of
+ true ->
+ set_vcard(User, LServer, Request),
+ exmpp_iq:result(IQ_Rec);
+ false ->
+ exmpp_iq:error(IQ_Rec, 'not-allowed')
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 = exmpp_xml:get_path(VCARD,
+ [{element, 'FN'}, cdata_as_list]),
+ Family = exmpp_xml:get_path(VCARD,
+ [{element, 'N'}, {element, 'FAMILY'}, cdata_as_list]),
+ Given = exmpp_xml:get_path(VCARD,
+ [{element, 'N'}, {element, 'GIVEN'}, cdata_as_list]),
+ Middle = exmpp_xml:get_path(VCARD,
+ [{element, 'N'}, {element, 'MIDDLE'}, cdata_as_list]),
+ Nickname = exmpp_xml:get_path(VCARD,
+ [{element, 'NICKNAME'}, cdata_as_list]),
+ BDay = exmpp_xml:get_path(VCARD,
+ [{element, 'BDAY'}, cdata_as_list]),
+ CTRY = exmpp_xml:get_path(VCARD,
+ [{element, 'ADR'}, {element, 'CTRY'}, cdata_as_list]),
+ Locality = exmpp_xml:get_path(VCARD,
+ [{element, 'ADR'}, {element, 'LOCALITY'}, cdata_as_list]),
+ EMail1 = exmpp_xml:get_path(VCARD,
+ [{element, 'EMAIL'}, {element, 'USERID'}, cdata_as_list]),
+ EMail2 = exmpp_xml:get_path(VCARD,
+ [{element, 'EMAIL'}, cdata_as_list]),
+ OrgName = exmpp_xml:get_path(VCARD,
+ [{element, 'ORG'}, {element, 'ORGNAME'}, cdata_as_list]),
+ OrgUnit = exmpp_xml:get_path(VCARD,
+ [{element, 'ORG'}, {element, 'ORGUNIT'}, cdata_as_list]),
EMail = case EMail1 of
"" ->
EMail2;
@@ -218,285 +232,257 @@ set_vcard(User, LServer, VCARD) ->
EMail1
end,
- LUser = jlib:nodeprep(User),
- LFN = stringprep:tolower(FN),
- LFamily = stringprep:tolower(Family),
- LGiven = stringprep:tolower(Given),
- LMiddle = stringprep:tolower(Middle),
- LNickname = stringprep:tolower(Nickname),
- LBDay = stringprep:tolower(BDay),
- LCTRY = stringprep:tolower(CTRY),
- LLocality = stringprep:tolower(Locality),
- LEMail = stringprep:tolower(EMail),
- LOrgName = stringprep:tolower(OrgName),
- LOrgUnit = stringprep:tolower(OrgUnit),
-
- US = {LUser, LServer},
-
- 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 ->
- 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)
+ try
+ LUser = exmpp_stringprep:nodeprep(User),
+ LFN = exmpp_stringprep:to_lower(FN),
+ LFamily = exmpp_stringprep:to_lower(Family),
+ LGiven = exmpp_stringprep:to_lower(Given),
+ LMiddle = exmpp_stringprep:to_lower(Middle),
+ LNickname = exmpp_stringprep:to_lower(Nickname),
+ LBDay = exmpp_stringprep:to_lower(BDay),
+ LCTRY = exmpp_stringprep:to_lower(CTRY),
+ LLocality = exmpp_stringprep:to_lower(Locality),
+ LEMail = exmpp_stringprep:to_lower(EMail),
+ LOrgName = exmpp_stringprep:to_lower(OrgName),
+ LOrgUnit = exmpp_stringprep:to_lower(OrgUnit),
+
+ 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)
+ catch
+ _ ->
+ {error, badarg}
end.
-define(TLFIELD(Type, Label, Var),
- {xmlelement, "field", [{"type", Type},
- {"label", translate:translate(Lang, Label)},
- {"var", Var}], []}).
+ #xmlel{ns = ?NS_VCARD, name = 'field', attrs = [
+ ?XMLATTR('type', Type),
+ ?XMLATTR('label', translate:translate(Lang, Label)),
+ ?XMLATTR('var', Var)]}).
-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{ns = ?NS_SEARCH, name = 'instructions', children =
+ [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "You need an x:data capable client to search"))}]},
+ #xmlel{ns = ?NS_DATA_FORMS, name = 'x', attrs =
+ [?XMLATTR('type', <<"form">>)], children =
+ [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children =
+ [#xmlcdata{cdata = list_to_binary(translate:translate(Lang, "Search users in ") ++ exmpp_jid:to_list(JID))}]},
+ #xmlel{ns = ?NS_SEARCH, name = 'instructions', children =
+ [#xmlcdata{cdata = list_to_binary(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,
+ User = exmpp_jid:node(To),
+ Resource = exmpp_jid:resource(To),
if
- (User /= "") or (Resource /= "") ->
- Err = jlib:make_error_reply(Packet, ?ERR_SERVICE_UNAVAILABLE),
+ (User /= undefined) or (Resource /= undefined) ->
+ Err = exmpp_stanza:reply_with_error(Packet, '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));
+ try
+ Request = exmpp_iq:get_request(Packet),
+ Type = exmpp_iq:get_type(Packet),
+ Lang = exmpp_stanza:get_lang(Packet),
+ case {Type, Request#xmlel.ns} of
+ {set, ?NS_SEARCH} ->
+ XDataEl = find_xdata_el(Request),
+ case XDataEl of
+ false ->
+ Err = exmpp_iq:error(Packet, 'bad-request'),
+ ejabberd_router:route(To, From, Err);
+ _ ->
+ XData = jlib:parse_xdata_submit(XDataEl),
+ case XData of
+ invalid ->
+ Err = exmpp_iq:error(Packet,
+ 'bad-request'),
+ ejabberd_router:route(To, From,
+ Err);
+ _ ->
+ Result = #xmlel{
+ ns = ?NS_SEARCH,
+ name = 'query',
+ children = [
+ #xmlel{
+ ns = ?NS_DATA_FORMS,
+ name = 'x',
+ attrs = [?XMLATTR('type',
+ <<"result">>)],
+ children = search_result(Lang,
+ To, ServerHost, XData)}]},
+ ResIQ = exmpp_iq:result(Packet,
+ Result),
+ ejabberd_router:route(
+ To, From, ResIQ)
+ end
+ end;
+ {get, ?NS_SEARCH} ->
+ Result = #xmlel{ns = ?NS_SEARCH, name = 'query',
+ children = ?FORM(To)},
+ ResIQ = exmpp_iq:result(Packet, Result),
+ ejabberd_router:route(To,
+ From,
+ ResIQ);
+ {set, ?NS_DISCO_INFO} ->
+ Err = exmpp_iq:error(Packet, 'not-allowed'),
+ ejabberd_router:route(To, From, Err);
+ {get, ?NS_DISCO_INFO} ->
+ ServerHostB = list_to_binary(ServerHost),
+ Info = ejabberd_hooks:run_fold(
+ disco_info, ServerHostB, [],
+ [ServerHost, ?MODULE, <<>>, ""]),
+ Result = #xmlel{ns = ?NS_DISCO_INFO, name = 'query',
+ children = Info ++ [
+ #xmlel{ns = ?NS_DISCO_INFO, name = 'identity',
+ attrs = [
+ ?XMLATTR('category', <<"directory">>),
+ ?XMLATTR('type', <<"user">>),
+ ?XMLATTR('name', translate:translate(Lang,
+ "vCard User Search"))]},
+ #xmlel{ns = ?NS_DISCO_INFO, name = 'feature',
+ attrs = [
+ ?XMLATTR('var', ?NS_DISCO_INFO_s)]},
+ #xmlel{ns = ?NS_DISCO_INFO, name = 'feature',
+ attrs = [
+ ?XMLATTR('var', ?NS_SEARCH_s)]},
+ #xmlel{ns = ?NS_DISCO_INFO, name = 'feature',
+ attrs = [
+ ?XMLATTR('var', ?NS_VCARD_s)]}
+ ]},
+ ResIQ = exmpp_iq:result(Packet, Result),
+ ejabberd_router:route(To,
+ From,
+ ResIQ);
+ {set, ?NS_DISCO_ITEMS} ->
+ Err = exmpp_iq:error(Packet, 'not-allowed'),
+ ejabberd_router:route(To, From, Err);
+ {get, ?NS_DISCO_ITEMS} ->
+ Result = #xmlel{ns = ?NS_DISCO_ITEMS, name = 'query'},
+ ResIQ = exmpp_iq:result(Packet, Result),
+ ejabberd_router:route(To,
+ From,
+ ResIQ);
+ {get, ?NS_VCARD} ->
+ Result = #xmlel{ns = ?NS_VCARD, name = 'vCard',
+ children = iq_get_vcard(Lang)},
+ ResIQ = exmpp_iq:result(Packet, Result),
+ ejabberd_router:route(To,
+ From,
+ ResIQ);
+ _ ->
+ Err = exmpp_iq:error(Packet, 'service-unavailable'),
+ ejabberd_router:route(To, From, Err)
+ end
+ catch
_ ->
- Err = jlib:make_error_reply(Packet,
- ?ERR_SERVICE_UNAVAILABLE),
- ejabberd_router:route(To, From, Err)
+ Err1 = exmpp_iq:error(Packet, 'service-unavailable'),
+ ejabberd_router:route(To, From, Err1)
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-2009 ProcessOne"}]}].
-
-find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) ->
+ [
+ #xmlel{ns = ?NS_SEARCH, name = 'FN', children = [
+ #xmlcdata{cdata = <<"ejabberd/mod_vcard">>}]},
+ #xmlel{ns = ?NS_SEARCH, name = 'URL', children = [
+ #xmlcdata{cdata = list_to_binary(?EJABBERD_URI)}]},
+ #xmlel{ns = ?NS_SEARCH, name ='DESC', children = [
+ #xmlcdata{cdata = list_to_binary(
+ translate:translate(Lang, "ejabberd vCard module") ++
+ "\nCopyright (c) 2003-2009 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)
- end;
+find_xdata_el1([#xmlel{ns = ?NS_DATA_FORMS} = El | _Els]) ->
+ El;
find_xdata_el1([_ | Els]) ->
find_xdata_el1(Els).
--define(LFIELD(Label, Var),
- {xmlelement, "field", [{"label", translate:translate(Lang, Label)},
- {"var", Var}], []}).
-
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")
+ [#xmlel{ns = ?NS_DATA_FORMS, name = 'title', children =
+ [#xmlcdata{cdata = list_to_binary(
+ translate:translate(Lang, "Search Results for ") ++
+ exmpp_jid:to_list(JID))}]},
+ #xmlel{ns = ?NS_DATA_FORMS, name = 'reported', 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 record_to_item/1, search(ServerHost, Data)).
-define(FIELD(Var, Val),
- {xmlelement, "field", [{"var", Var}],
- [{xmlelement, "value", [],
- [{xmlcdata, Val}]}]}).
+ #xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs =
+ [?XMLATTR('var', Var)], children =
+ [#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children =
+ [#xmlcdata{cdata = Val}]}]}).
record_to_item(R) ->
{User, Server} = R#vcard_search.user,
- {xmlelement, "item", [],
+ #xmlel{ns = ?NS_DATA_FORMS, name = 'item', children =
[
- ?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)
+ ?FIELD(<<"jid">>, list_to_binary(User ++ "@" ++ Server)),
+ ?FIELD(<<"fn">>, list_to_binary(R#vcard_search.fn)),
+ ?FIELD(<<"last">>, list_to_binary(R#vcard_search.family)),
+ ?FIELD(<<"first">>, list_to_binary(R#vcard_search.given)),
+ ?FIELD(<<"middle">>, list_to_binary(R#vcard_search.middle)),
+ ?FIELD(<<"nick">>, list_to_binary(R#vcard_search.nickname)),
+ ?FIELD(<<"bday">>, list_to_binary(R#vcard_search.bday)),
+ ?FIELD(<<"ctry">>, list_to_binary(R#vcard_search.ctry)),
+ ?FIELD(<<"locality">>, list_to_binary(R#vcard_search.locality)),
+ ?FIELD(<<"email">>, list_to_binary(R#vcard_search.email)),
+ ?FIELD(<<"orgname">>, list_to_binary(R#vcard_search.orgname)),
+ ?FIELD(<<"orgunit">>, list_to_binary(R#vcard_search.orgunit))
]
}.
@@ -540,7 +526,7 @@ filter_fields([], Match, _LServer) ->
Match;
filter_fields([{SVar, [Val]} | Ds], Match, LServer)
when is_list(Val) and (Val /= "") ->
- LVal = stringprep:tolower(Val),
+ LVal = exmpp_stringprep:to_lower(Val),
NewMatch = case SVar of
"user" ->
case gen_mod:get_module_opt(LServer, ?MODULE,
@@ -604,61 +590,60 @@ set_vcard_t(R, _) ->
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]),
-
- {LUser, _LServer} = US,
- LFN = stringprep:tolower(FN),
- LFamily = stringprep:tolower(Family),
- LGiven = stringprep:tolower(Given),
- LMiddle = stringprep:tolower(Middle),
- LNickname = stringprep:tolower(Nickname),
- LBDay = stringprep:tolower(BDay),
- LCTRY = stringprep:tolower(CTRY),
- LLocality = stringprep:tolower(Locality),
- LEMail = stringprep:tolower(EMail),
- LOrgName = stringprep:tolower(OrgName),
- LOrgUnit = stringprep:tolower(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
- })
+ FN = exmpp_xml:get_path(VCARD,
+ [{element, 'FN'}, cdata_as_list]),
+ Family = exmpp_xml:get_path(VCARD,
+ [{element, 'N'}, {element, 'FAMILY'}, cdata_as_list]),
+ Given = exmpp_xml:get_path(VCARD,
+ [{element, 'N'}, {element, 'GIVEN'}, cdata_as_list]),
+ Middle = exmpp_xml:get_path(VCARD,
+ [{element, 'N'}, {element, 'MIDDLE'}, cdata_as_list]),
+ Nickname = exmpp_xml:get_path(VCARD,
+ [{element, 'NICKNAME'}, cdata_as_list]),
+ BDay = exmpp_xml:get_path(VCARD,
+ [{element, 'BDAY'}, cdata_as_list]),
+ CTRY = exmpp_xml:get_path(VCARD,
+ [{element, 'ADR'}, {element, 'CTRY'}, cdata_as_list]),
+ Locality = exmpp_xml:get_path(VCARD,
+ [{element, 'ADR'}, {element, 'LOCALITY'},cdata_as_list]),
+ EMail = exmpp_xml:get_path(VCARD,
+ [{element, 'EMAIL'}, cdata_as_list]),
+ OrgName = exmpp_xml:get_path(VCARD,
+ [{element, 'ORG'}, {element, 'ORGNAME'}, cdata_as_list]),
+ OrgUnit = exmpp_xml:get_path(VCARD,
+ [{element, 'ORG'}, {element, 'ORGUNIT'}, cdata_as_list]),
+
+ try
+ {LUser, _LServer} = US,
+ LFN = exmpp_stringprep:to_lower(FN),
+ LFamily = exmpp_stringprep:to_lower(Family),
+ LGiven = exmpp_stringprep:to_lower(Given),
+ LMiddle = exmpp_stringprep:to_lower(Middle),
+ LNickname = exmpp_stringprep:to_lower(Nickname),
+ LBDay = exmpp_stringprep:to_lower(BDay),
+ LCTRY = exmpp_stringprep:to_lower(CTRY),
+ LLocality = exmpp_stringprep:to_lower(Locality),
+ LEMail = exmpp_stringprep:to_lower(EMail),
+ LOrgName = exmpp_stringprep:to_lower(OrgName),
+ LOrgUnit = exmpp_stringprep:to_lower(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
+ })
+ catch
+ _ ->
+ {error, badarg}
end.
@@ -669,9 +654,9 @@ reindex_vcards() ->
mnesia:transaction(F).
-remove_user(User, Server) ->
- LUser = jlib:nodeprep(User),
- LServer = jlib:nameprep(Server),
+remove_user(User, Server) when is_binary(User), is_binary(Server) ->
+ LUser = exmpp_stringprep:nodeprep(User),
+ LServer = exmpp_stringprep:nameprep(Server),
US = {LUser, LServer},
F = fun() ->
mnesia:delete({vcard, US}),
@@ -688,7 +673,7 @@ update_vcard_table() ->
Fields = record_info(fields, vcard),
case mnesia:table_info(vcard, attributes) of
Fields ->
- ok;
+ convert_to_exmpp();
[user, vcard] ->
?INFO_MSG("Converting vcard table from "
"{user, vcard} format", []),
@@ -727,6 +712,29 @@ update_vcard_table() ->
end.
+convert_to_exmpp() ->
+ Fun = fun() ->
+ case mnesia:first(vcard) of
+ '$end_of_table' ->
+ none;
+ Key ->
+ case mnesia:read({vcard, Key}) of
+ [#vcard{vcard = #xmlel{}}] ->
+ none;
+ [#vcard{vcard = #xmlelement{}}] ->
+ mnesia:foldl(fun convert_to_exmpp2/2,
+ done, vcard, write)
+ end
+ end
+ end,
+ mnesia:transaction(Fun).
+
+convert_to_exmpp2(#vcard{vcard = ElOld} = VCard, Acc) ->
+ El0 = exmpp_xml:xmlelement_to_xmlel(ElOld, [?NS_VCARD], []),
+ El = exmpp_xml:remove_whitespaces_deeply(El0),
+ mnesia:write(VCard#vcard{vcard = El}),
+ Acc.
+
update_vcard_search_table() ->
Fields = record_info(fields, vcard_search),
case mnesia:table_info(vcard_search, attributes) of