25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-12-22 17:28:25 +01:00

* src/ejd2odbc.erl: Added vCard converter

* src/mod_vcard_odbc.erl: vCard support via ODBC

* src/odbc/pg.sql: Updated

SVN Revision: 414
This commit is contained in:
Alexey Shchepin 2005-10-06 23:57:34 +00:00
parent 0291cac0f5
commit 108b2646ee
4 changed files with 826 additions and 47 deletions

View File

@ -1,3 +1,11 @@
2005-10-07 Alexey Shchepin <alexey@sevcom.net>
* src/ejd2odbc.erl: Added vCard converter
* src/mod_vcard_odbc.erl: vCard support via ODBC
* src/odbc/pg.sql: Updated
2005-09-18 Alexey Shchepin <alexey@sevcom.net>
* src/web/ejabberd_web_admin.erl: Updated API for better

View File

@ -14,7 +14,9 @@
-export([export_passwd/2,
export_roster/2,
export_offline/2,
export_last/2]).
export_last/2,
export_vcard/2,
export_vcard_search/2]).
-include("ejabberd.hrl").
-include("jlib.hrl").
@ -22,6 +24,21 @@
-record(offline_msg, {us, timestamp, expire, from, to, packet}).
-record(last_activity, {us, timestamp, status}).
-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
}).
-define(MAX_RECORDS_PER_TRANSACTION, 1000).
@ -119,6 +136,89 @@ export_last(Server, Output) ->
[]
end).
export_vcard(Server, Output) ->
export_common(
Server, vcard, Output,
fun(Host, #vcard{us = {LUser, LServer},
vcard = VCARD})
when LServer == Host ->
Username = ejabberd_odbc:escape(LUser),
SVCARD = ejabberd_odbc:escape(
lists:flatten(xml:element_to_string(VCARD))),
["delete from vcard where username='", Username, "';"
"insert into vcard(username, vcard) "
"values ('", Username, "', '", SVCARD, "');"];
(_Host, _R) ->
[]
end).
export_vcard_search(Server, Output) ->
export_common(
Server, vcard_search, Output,
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).
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------

670
src/mod_vcard_odbc.erl Normal file
View File

@ -0,0 +1,670 @@
%%%----------------------------------------------------------------------
%%% File : mod_vcard.erl
%%% Author : Alexey Shchepin <alexey@sevcom.net>
%%% Purpose : vCard support via ODBC
%%% Created : 2 Jan 2003 by Alexey Shchepin <alexey@sevcom.net>
%%% Id : $Id: mod_vcard.erl 374 2005-07-13 03:24:13Z alexey $
%%%----------------------------------------------------------------------
-module(mod_vcard_odbc).
-author('alexey@sevcom.net').
-vsn('$Revision: 374 $ ').
-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]).
-include("ejabberd.hrl").
-include("jlib.hrl").
-define(JUD_MATCHES, 30).
-define(PROCNAME, ejabberd_mod_vcard).
start(Host, Opts) ->
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, Opts, "vjud." ++ Host),
Search = gen_mod:get_opt(search, Opts, 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)
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)
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),
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
Proc ! stop,
{wait, Proc}.
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
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,
"http://ejabberd.jabberstudio.org/"}]},
{xmlelement, "DESC", [],
[{xmlcdata,
translate:translate(
Lang,
"Erlang Jabber Server\n"
"Copyright (c) 2002-2005 Alexey Shchepin")}]},
{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},
Username = ejabberd_odbc:escape(LUser),
case catch ejabberd_odbc:sql_query(
LServer,
["select vcard from vcard "
"where username='", Username, "'"]) of
{selected, ["vcard"], [{SVCARD}]} ->
case xml_stream:parse_element(SVCARD) of
{error, _Reason} ->
IQ#iq{type = error,
sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]};
VCARD ->
IQ#iq{type = result, sub_el = [VCARD]}
end;
{selected, ["vcard"], []} ->
IQ#iq{type = result, sub_el = []};
{'EXIT', _Reason} ->
IQ#iq{type = error,
sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}
end
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]),
EMail = case EMail1 of
"" ->
EMail2;
_ ->
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 ->
Username = ejabberd_odbc:escape(User),
LUsername = ejabberd_odbc:escape(LUser),
SVCARD = ejabberd_odbc:escape(
lists:flatten(xml:element_to_string(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),
ejabberd_odbc:sql_query(
LServer,
["begin;"
"delete from vcard where username='", LUsername, "';"
"insert into vcard(username, vcard) "
"values ('", LUsername, "', '", SVCARD, "');"
"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, "');"
"commit"])
end.
-define(TLFIELD(Type, Label, Var),
{xmlelement, "field", [{"type", Type},
{"label", translate:translate(Lang, Label)},
{"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", "given"),
?TLFIELD("text-single", "Middle Name", "middle"),
?TLFIELD("text-single", "Family Name", "family"),
?TLFIELD("text-single", "Nickname", "nickname"),
?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} ->
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_INFO}],
[{xmlelement, "identity",
[{"category", "directory"},
{"type", "user"},
{"name",
"vCard User Search"}],
[]},
{xmlelement, "feature",
[{"var", ?NS_SEARCH}], []},
{xmlelement, "feature",
[{"var", ?NS_VCARD}], []}
]
}]},
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_INFO}],
[]}]},
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
end.
iq_get_vcard(Lang) ->
[{xmlelement, "FN", [],
[{xmlcdata, "ejabberd/mod_vcard"}]},
{xmlelement, "URL", [],
[{xmlcdata,
"http://ejabberd.jabberstudio.org/"}]},
{xmlelement, "DESC", [],
[{xmlcdata, translate:translate(
Lang,
"ejabberd vCard module\n"
"Copyright (c) 2003-2005 Alexey Shchepin")}]}].
find_xdata_el({xmlelement, _Name, _Attrs, 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([_ | 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, "Results of search in ") ++
jlib:jid_to_string(JID)}]},
{xmlelement, "reported", [],
[?LFIELD("JID", "jid"),
?LFIELD("Full Name", "fn"),
?LFIELD("Name", "given"),
?LFIELD("Middle Name", "middle"),
?LFIELD("Family Name", "family"),
?LFIELD("Nickname", "nickname"),
?LFIELD("Birthday", "bday"),
?LFIELD("Country", "ctry"),
?LFIELD("City", "locality"),
?LFIELD("email", "email"),
?LFIELD("Organization Name", "orgname"),
?LFIELD("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("family", Family),
?FIELD("given", Given),
?FIELD("middle", Middle),
?FIELD("nickname", Nickname),
?FIELD("bday", BDay),
?FIELD("ctry", CTRY),
?FIELD("locality", Locality),
?FIELD("email", EMail),
?FIELD("orgname", OrgName),
?FIELD("orgunit", OrgUnit)
]
}.
search(LServer, Data) ->
MatchSpec = make_matchspec(LServer, Data),
AllowReturnAll = gen_mod:get_module_opt(LServer, ?MODULE,
allow_return_all, false),
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
end.
make_matchspec(LServer, Data) ->
filter_fields(Data, "", LServer).
filter_fields([], Match, _LServer) ->
case Match of
"" ->
"";
_ ->
[" where ", Match]
end;
filter_fields([{SVar, [Val]} | Ds], Match, LServer)
when is_list(Val) and (Val /= "") ->
LVal = stringprep:tolower(Val),
NewMatch = case SVar of
"user" -> make_val(Match, "lusername", LVal);
"fn" -> make_val(Match, "lfn", LVal);
"family" -> make_val(Match, "lfamily", LVal);
"given" -> make_val(Match, "lgiven", LVal);
"middle" -> make_val(Match, "lmiddle", LVal);
"nickname" -> 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);
filter_fields([_ | Ds], Match, LServer) ->
filter_fields(Ds, Match, LServer).
make_val(Match, Field, Val) ->
Condition =
case lists:suffix("*", Val) of
true ->
Val1 = lists:sublist(Val, length(Val) - 1),
Val2 = lists:flatten([case C of
$_ -> "\\_";
$% -> "\\%";
_ -> C
end || C <- Val1]),
SVal = ejabberd_odbc:escape(Val2 ++ "%"),
[Field, " LIKE '", SVal, "'"];
_ ->
SVal = ejabberd_odbc:escape(Val),
[Field, " = '", SVal, "'"]
end,
case Match of
"" ->
Condition;
_ ->
[Match, " and ", Condition]
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%set_vcard_t(R, _) ->
% US = R#vcard.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]),
%
% {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
% })
% end.
%
%
%reindex_vcards() ->
% 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),
Username = ejabberd_odbc:escape(LUser),
ejabberd_odbc:sql_query(
LServer,
["begin;"
"delete from vcard where username='", Username, "';"
"delete from vcard_search where lusername='", Username, "';"
"commit"]).

View File

@ -1,13 +1,12 @@
CREATE TABLE users (
username text NOT NULL,
username text PRIMARY KEY,
"password" text NOT NULL
);
CREATE TABLE last (
username text NOT NULL,
username text PRIMARY KEY,
seconds text NOT NULL,
state text
);
@ -24,6 +23,9 @@ CREATE TABLE rosterusers (
"type" text
);
CREATE UNIQUE INDEX i_rosteru_user_jid ON rosterusers USING btree (username, jid);
CREATE INDEX i_rosteru_username ON rosterusers USING btree (username);
CREATE INDEX i_rosteru_jid ON rosterusers USING btree (jid);
CREATE TABLE rostergroups (
@ -32,58 +34,57 @@ CREATE TABLE rostergroups (
grp text NOT NULL
);
CREATE INDEX pk_rosterg_user_jid ON rostergroups USING btree (username, jid);
CREATE TABLE spool (
username text NOT NULL,
xml text
);
CREATE INDEX i_despool ON spool USING btree (username);
CREATE TABLE vcard (
username text NOT NULL,
full_name text,
first_name text,
last_name text,
nick_name text,
url text,
address1 text,
address2 text,
locality text,
region text,
pcode text,
country text,
telephone text,
email text,
orgname text,
orgunit text,
title text,
role text,
b_day date,
descr text
username text PRIMARY KEY,
vcard text NOT NULL
);
CREATE TABLE vcard_search (
username text NOT NULL,
lusername text PRIMARY KEY,
fn text NOT NULL,
lfn text NOT NULL,
family text NOT NULL,
lfamily text NOT NULL,
given text NOT NULL,
lgiven text NOT NULL,
middle text NOT NULL,
lmiddle text NOT NULL,
nickname text NOT NULL,
lnickname text NOT NULL,
bday text NOT NULL,
lbday text NOT NULL,
ctry text NOT NULL,
lctry text NOT NULL,
locality text NOT NULL,
llocality text NOT NULL,
email text NOT NULL,
lemail text NOT NULL,
orgname text NOT NULL,
lorgname text NOT NULL,
orgunit text NOT NULL,
lorgunit text NOT NULL
);
CREATE INDEX i_users_login ON users USING btree (username, "password");
CREATE INDEX i_rosteru_user_jid ON rosterusers USING btree (username, jid);
CREATE INDEX i_rosteru_username ON rosterusers USING btree (username);
CREATE INDEX pk_rosterg_user_jid ON rostergroups USING btree (username, jid);
CREATE INDEX i_despool ON spool USING btree (username);
CREATE INDEX i_rosteru_jid ON rosterusers USING btree (jid);
ALTER TABLE ONLY users
ADD CONSTRAINT users_pkey PRIMARY KEY (username);
ALTER TABLE ONLY last
ADD CONSTRAINT last_pkey PRIMARY KEY (username);
ALTER TABLE ONLY vcard
ADD CONSTRAINT vcard_pkey PRIMARY KEY (username);
CREATE INDEX i_vcard_search_lfn ON vcard_search(lfn);
CREATE INDEX i_vcard_search_lfamily ON vcard_search(lfamily);
CREATE INDEX i_vcard_search_lgiven ON vcard_search(lgiven);
CREATE INDEX i_vcard_search_lmiddle ON vcard_search(lmiddle);
CREATE INDEX i_vcard_search_lnickname ON vcard_search(lnickname);
CREATE INDEX i_vcard_search_lbday ON vcard_search(lbday);
CREATE INDEX i_vcard_search_lctry ON vcard_search(lctry);
CREATE INDEX i_vcard_search_llocality ON vcard_search(llocality);
CREATE INDEX i_vcard_search_lemail ON vcard_search(lemail);
CREATE INDEX i_vcard_search_lorgname ON vcard_search(lorgname);
CREATE INDEX i_vcard_search_lorgunit ON vcard_search(lorgunit);