mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-28 16:34:13 +01:00
* src/odbc/pg.sql: DB creation script for postgres
* src/odbc/ejabberd_odbc.erl: Experimental support for ODBC * src/mod_last_odbc.erl: Likewise * src/mod_offline_odbc.erl: Likewise * src/ejabberd_auth_odbc.erl: Likewise * src/ejabberd_auth.erl: Likewise SVN Revision: 292
This commit is contained in:
parent
0e9f506a91
commit
8c8e3469bc
10
ChangeLog
10
ChangeLog
@ -1,3 +1,13 @@
|
||||
2004-12-13 Alexey Shchepin <alexey@sevcom.net>
|
||||
|
||||
* src/odbc/pg.sql: DB creation script for postgres
|
||||
|
||||
* src/odbc/ejabberd_odbc.erl: Experimental support for ODBC
|
||||
* src/mod_last_odbc.erl: Likewise
|
||||
* src/mod_offline_odbc.erl: Likewise
|
||||
* src/ejabberd_auth_odbc.erl: Likewise
|
||||
* src/ejabberd_auth.erl: Likewise
|
||||
|
||||
2004-12-12 Alexey Shchepin <alexey@sevcom.net>
|
||||
|
||||
* src/mod_stats.erl: Minor optimizations
|
||||
|
@ -74,6 +74,8 @@ auth_module() ->
|
||||
ejabberd_auth_external;
|
||||
ldap ->
|
||||
ejabberd_auth_ldap;
|
||||
odbc ->
|
||||
ejabberd_auth_odbc;
|
||||
_ ->
|
||||
ejabberd_auth_internal
|
||||
end.
|
||||
|
210
src/ejabberd_auth_odbc.erl
Normal file
210
src/ejabberd_auth_odbc.erl
Normal file
@ -0,0 +1,210 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : ejabberd_auth_odbc.erl
|
||||
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Purpose : Authentification via ODBC
|
||||
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Id : $Id$
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(ejabberd_auth_odbc).
|
||||
-author('alexey@sevcom.net').
|
||||
-vsn('$Revision$ ').
|
||||
|
||||
%% External exports
|
||||
-export([start/0,
|
||||
set_password/2,
|
||||
check_password/2,
|
||||
check_password/4,
|
||||
try_register/2,
|
||||
dirty_get_registered_users/0,
|
||||
get_password/1,
|
||||
get_password_s/1,
|
||||
is_user_exists/1,
|
||||
remove_user/1,
|
||||
remove_user/2,
|
||||
plain_password_required/0
|
||||
]).
|
||||
|
||||
-record(passwd, {user, password}).
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% API
|
||||
%%%----------------------------------------------------------------------
|
||||
start() ->
|
||||
ok.
|
||||
|
||||
plain_password_required() ->
|
||||
false.
|
||||
|
||||
check_password(User, Password) ->
|
||||
case jlib:nodeprep(User) of
|
||||
error ->
|
||||
false;
|
||||
LUser ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
case catch ejabberd_odbc:sql_query(
|
||||
["select password from users "
|
||||
"where username='", Username, "'"]) of
|
||||
{selected, ["password"], [{Password}]} ->
|
||||
true;
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end.
|
||||
|
||||
check_password(User, Password, StreamID, Digest) ->
|
||||
case jlib:nodeprep(User) of
|
||||
error ->
|
||||
false;
|
||||
LUser ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
case catch ejabberd_odbc:sql_query(
|
||||
["select password from users "
|
||||
"where username='", Username, "'"]) of
|
||||
{selected, ["password"], [{Passwd}]} ->
|
||||
DigRes = if
|
||||
Digest /= "" ->
|
||||
Digest == sha:sha(StreamID ++ Passwd);
|
||||
true ->
|
||||
false
|
||||
end,
|
||||
if DigRes ->
|
||||
true;
|
||||
true ->
|
||||
(Passwd == Password) and (Password /= "")
|
||||
end;
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end.
|
||||
|
||||
set_password(User, Password) ->
|
||||
case jlib:nodeprep(User) of
|
||||
error ->
|
||||
{error, invalid_jid};
|
||||
LUser ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
Pass = ejabberd_odbc:escape(Password),
|
||||
catch ejabberd_odbc:sql_query(
|
||||
["begin;"
|
||||
"delete from users where username='", Username ,"';"
|
||||
"insert into users(username, password) "
|
||||
"values ('", Username, "', '", Pass, "'); commit"])
|
||||
end.
|
||||
|
||||
|
||||
try_register(User, Password) ->
|
||||
case jlib:nodeprep(User) of
|
||||
error ->
|
||||
{error, invalid_jid};
|
||||
LUser ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
Pass = ejabberd_odbc:escape(Password),
|
||||
case catch ejabberd_odbc:sql_query(
|
||||
["insert into users(username, password) "
|
||||
"values ('", Username, "', '", Pass, "')"]) of
|
||||
{updated, _} ->
|
||||
{atomic, ok};
|
||||
_ ->
|
||||
{atomic, exists}
|
||||
end
|
||||
end.
|
||||
|
||||
dirty_get_registered_users() ->
|
||||
case catch ejabberd_odbc:sql_query("select username from users") of
|
||||
{selected, ["username"], Res} ->
|
||||
[U || {U} <- Res];
|
||||
_ ->
|
||||
[]
|
||||
end.
|
||||
|
||||
get_password(User) ->
|
||||
case jlib:nodeprep(User) of
|
||||
error ->
|
||||
false;
|
||||
LUser ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
case catch ejabberd_odbc:sql_query(
|
||||
["select password from users "
|
||||
"where username='", Username, "'"]) of
|
||||
{selected, ["password"], [{Password}]} ->
|
||||
Password;
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end.
|
||||
|
||||
get_password_s(User) ->
|
||||
case jlib:nodeprep(User) of
|
||||
error ->
|
||||
"";
|
||||
LUser ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
case catch ejabberd_odbc:sql_query(
|
||||
["select password from users "
|
||||
"where username='", Username, "'"]) of
|
||||
{selected, ["password"], [{Password}]} ->
|
||||
Password;
|
||||
_ ->
|
||||
""
|
||||
end
|
||||
end.
|
||||
|
||||
is_user_exists(User) ->
|
||||
case jlib:nodeprep(User) of
|
||||
error ->
|
||||
false;
|
||||
LUser ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
case catch ejabberd_odbc:sql_query(
|
||||
["select password from users "
|
||||
"where username='", Username, "'"]) of
|
||||
{selected, ["password"], [{_Password}]} ->
|
||||
true;
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end.
|
||||
|
||||
remove_user(User) ->
|
||||
case jlib:nodeprep(User) of
|
||||
error ->
|
||||
error;
|
||||
LUser ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
catch ejabberd_odbc:sql_query(
|
||||
["delete from users where username='", Username ,"'"]),
|
||||
catch mod_roster:remove_user(User),
|
||||
catch mod_offline:remove_user(User),
|
||||
catch mod_last:remove_user(User),
|
||||
catch mod_vcard:remove_user(User),
|
||||
catch mod_private:remove_user(User)
|
||||
end.
|
||||
|
||||
remove_user(User, Password) ->
|
||||
case jlib:nodeprep(User) of
|
||||
error ->
|
||||
error;
|
||||
LUser ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
Pass = ejabberd_odbc:escape(Password),
|
||||
case catch
|
||||
ejabberd_odbc:sql_query(
|
||||
["begin;"
|
||||
"select password from users where username='", Username, "';"
|
||||
"delete from users "
|
||||
"where username='", Username, "' and password='", Pass, "';"
|
||||
"commit"]) of
|
||||
{selected, ["password"], [{Password}]} ->
|
||||
catch mod_roster:remove_user(User),
|
||||
catch mod_offline:remove_user(User),
|
||||
catch mod_last:remove_user(User),
|
||||
catch mod_vcard:remove_user(User),
|
||||
catch mod_private:remove_user(User),
|
||||
ok;
|
||||
{selected, ["password"], []} ->
|
||||
not_exists;
|
||||
_ ->
|
||||
not_allowed
|
||||
end
|
||||
end.
|
135
src/mod_last_odbc.erl
Normal file
135
src/mod_last_odbc.erl
Normal file
@ -0,0 +1,135 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : mod_last_odbc.erl
|
||||
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Purpose : jabber:iq:last support (JEP-0012)
|
||||
%%% Created : 24 Oct 2003 by Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Id : $Id$
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(mod_last_odbc).
|
||||
-author('alexey@sevcom.net').
|
||||
-vsn('$Revision$ ').
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start/1,
|
||||
stop/0,
|
||||
process_local_iq/3,
|
||||
process_sm_iq/3,
|
||||
on_presence_update/3,
|
||||
remove_user/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
|
||||
|
||||
start(Opts) ->
|
||||
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_LAST,
|
||||
?MODULE, process_local_iq, IQDisc),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_LAST,
|
||||
?MODULE, process_sm_iq, IQDisc),
|
||||
ejabberd_hooks:add(unset_presence_hook,
|
||||
?MODULE, on_presence_update, 50).
|
||||
|
||||
stop() ->
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_LAST),
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_LAST).
|
||||
|
||||
process_local_iq(_From, _To, #iq{type = Type, sub_el = SubEl} = IQ) ->
|
||||
case Type of
|
||||
set ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
||||
get ->
|
||||
Sec = trunc(element(1, erlang:statistics(wall_clock))/1000),
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", ?NS_LAST},
|
||||
{"seconds", integer_to_list(Sec)}],
|
||||
[]}]}
|
||||
end.
|
||||
|
||||
|
||||
process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
|
||||
case Type of
|
||||
set ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
|
||||
get ->
|
||||
User = To#jid.luser,
|
||||
{Subscription, _Groups} =
|
||||
mod_roster:get_jid_info(User, From),
|
||||
if
|
||||
(Subscription == both) or (Subscription == from) ->
|
||||
case catch mod_privacy:get_user_list(User) of
|
||||
{'EXIT', _Reason} ->
|
||||
get_last(IQ, SubEl, User);
|
||||
List ->
|
||||
case catch mod_privacy:check_packet(
|
||||
User, List,
|
||||
{From, To,
|
||||
{xmlelement, "presence", [], []}},
|
||||
out) of
|
||||
{'EXIT', _Reason} ->
|
||||
get_last(IQ, SubEl, User);
|
||||
allow ->
|
||||
get_last(IQ, SubEl, User);
|
||||
deny ->
|
||||
IQ#iq{type = error,
|
||||
sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
|
||||
end
|
||||
end;
|
||||
true ->
|
||||
IQ#iq{type = error,
|
||||
sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
|
||||
end
|
||||
end.
|
||||
|
||||
get_last(IQ, SubEl, LUser) ->
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
case catch ejabberd_odbc:sql_query(
|
||||
["select seconds, state from last "
|
||||
"where username='", Username, "'"]) of
|
||||
{'EXIT', _Reason} ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]};
|
||||
{selected, ["seconds","state"], []} ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]};
|
||||
{selected, ["seconds","state"], [{STimeStamp, Status}]} ->
|
||||
case catch list_to_integer(STimeStamp) of
|
||||
TimeStamp when is_integer(TimeStamp) ->
|
||||
{MegaSecs, Secs, _MicroSecs} = now(),
|
||||
TimeStamp2 = MegaSecs * 1000000 + Secs,
|
||||
Sec = TimeStamp2 - TimeStamp,
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", ?NS_LAST},
|
||||
{"seconds", integer_to_list(Sec)}],
|
||||
[{xmlcdata, Status}]}]};
|
||||
_ ->
|
||||
IQ#iq{type = error,
|
||||
sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}
|
||||
end
|
||||
end.
|
||||
|
||||
|
||||
|
||||
on_presence_update(User, _Resource, Status) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
{MegaSecs, Secs, _MicroSecs} = now(),
|
||||
TimeStamp = MegaSecs * 1000000 + Secs,
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
Seconds = ejabberd_odbc:escape(integer_to_list(TimeStamp)),
|
||||
State = ejabberd_odbc:escape(Status),
|
||||
ejabberd_odbc:sql_query(
|
||||
["begin;"
|
||||
"delete from last where username='", Username, "';"
|
||||
"insert into last(username, seconds, state) "
|
||||
"values ('", Username, "', '", Seconds, "', '", State, "');",
|
||||
"commit"]).
|
||||
|
||||
|
||||
remove_user(User) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
ejabberd_odbc:sql_query(
|
||||
["delete from last where username='", Username, "'"]).
|
||||
|
242
src/mod_offline_odbc.erl
Normal file
242
src/mod_offline_odbc.erl
Normal file
@ -0,0 +1,242 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : mod_offline_odbc.erl
|
||||
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Purpose :
|
||||
%%% Created : 5 Jan 2003 by Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Id : $Id$
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(mod_offline_odbc).
|
||||
-author('alexey@sevcom.net').
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start/1,
|
||||
init/0,
|
||||
stop/0,
|
||||
store_packet/3,
|
||||
pop_offline_messages/2,
|
||||
remove_user/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
|
||||
-record(offline_msg, {user, timestamp, expire, from, to, packet}).
|
||||
|
||||
-define(PROCNAME, ejabberd_offline).
|
||||
-define(OFFLINE_TABLE_LOCK_THRESHOLD, 1000).
|
||||
|
||||
start(_) ->
|
||||
% TODO: remove
|
||||
ejabberd_odbc:start(),
|
||||
ejabberd_hooks:add(offline_message_hook,
|
||||
?MODULE, store_packet, 50),
|
||||
ejabberd_hooks:add(offline_subscription_hook,
|
||||
?MODULE, store_packet, 50),
|
||||
ejabberd_hooks:add(resend_offline_messages_hook,
|
||||
?MODULE, pop_offline_messages, 50),
|
||||
register(?PROCNAME, spawn(?MODULE, init, [])).
|
||||
|
||||
init() ->
|
||||
loop().
|
||||
|
||||
loop() ->
|
||||
receive
|
||||
#offline_msg{} = Msg ->
|
||||
Msgs = receive_all([Msg]),
|
||||
% TODO
|
||||
Query = lists:map(
|
||||
fun(M) ->
|
||||
Username =
|
||||
ejabberd_odbc:escape(
|
||||
(M#offline_msg.to)#jid.luser),
|
||||
From = M#offline_msg.from,
|
||||
To = M#offline_msg.to,
|
||||
{xmlelement, Name, Attrs, Els} =
|
||||
M#offline_msg.packet,
|
||||
Attrs2 = jlib:replace_from_to_attrs(
|
||||
jlib:jid_to_string(From),
|
||||
jlib:jid_to_string(To),
|
||||
Attrs),
|
||||
Packet = {xmlelement, Name, Attrs2,
|
||||
Els ++
|
||||
[jlib:timestamp_to_xml(
|
||||
calendar:now_to_universal_time(
|
||||
M#offline_msg.timestamp))]},
|
||||
XML =
|
||||
ejabberd_odbc:escape(
|
||||
lists:flatten(
|
||||
xml:element_to_string(Packet))),
|
||||
["insert into spool(username, xml) "
|
||||
"values ('", Username, "', '",
|
||||
XML,
|
||||
"');"]
|
||||
end, Msgs),
|
||||
case catch ejabberd_odbc:sql_query(
|
||||
["begin; ", Query, " commit"]) of
|
||||
{'EXIT', Reason} ->
|
||||
?ERROR_MSG("~p~n", [Reason]);
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
loop();
|
||||
_ ->
|
||||
loop()
|
||||
end.
|
||||
|
||||
receive_all(Msgs) ->
|
||||
receive
|
||||
#offline_msg{} = Msg ->
|
||||
receive_all([Msg | Msgs])
|
||||
after 0 ->
|
||||
Msgs
|
||||
end.
|
||||
|
||||
|
||||
stop() ->
|
||||
ejabberd_hooks:delete(offline_message_hook,
|
||||
?MODULE, store_packet, 50),
|
||||
ejabberd_hooks:delete(offline_subscription_hook,
|
||||
?MODULE, store_packet, 50),
|
||||
ejabberd_hooks:delete(resend_offline_messages_hook,
|
||||
?MODULE, pop_offline_messages, 50),
|
||||
exit(whereis(?PROCNAME), stop),
|
||||
ok.
|
||||
|
||||
store_packet(From, To, Packet) ->
|
||||
Type = xml:get_tag_attr_s("type", Packet),
|
||||
if
|
||||
(Type /= "error") and (Type /= "groupchat") ->
|
||||
case check_event(From, To, Packet) of
|
||||
true ->
|
||||
#jid{luser = LUser} = To,
|
||||
TimeStamp = now(),
|
||||
{xmlelement, _Name, _Attrs, Els} = Packet,
|
||||
Expire = find_x_expire(TimeStamp, Els),
|
||||
?PROCNAME ! #offline_msg{user = LUser,
|
||||
timestamp = TimeStamp,
|
||||
expire = Expire,
|
||||
from = From,
|
||||
to = To,
|
||||
packet = Packet},
|
||||
stop;
|
||||
_ ->
|
||||
ok
|
||||
end;
|
||||
true ->
|
||||
ok
|
||||
end.
|
||||
|
||||
check_event(From, To, Packet) ->
|
||||
{xmlelement, Name, Attrs, Els} = Packet,
|
||||
case find_x_event(Els) of
|
||||
false ->
|
||||
true;
|
||||
El ->
|
||||
case xml:get_subtag(El, "id") of
|
||||
false ->
|
||||
case xml:get_subtag(El, "offline") of
|
||||
false ->
|
||||
true;
|
||||
_ ->
|
||||
ID = case xml:get_tag_attr_s("id", Packet) of
|
||||
"" ->
|
||||
{xmlelement, "id", [], []};
|
||||
S ->
|
||||
{xmlelement, "id", [],
|
||||
[{xmlcdata, S}]}
|
||||
end,
|
||||
ejabberd_router:route(
|
||||
To, From, {xmlelement, Name, Attrs,
|
||||
[{xmlelement, "x",
|
||||
[{"xmlns", ?NS_EVENT}],
|
||||
[ID,
|
||||
{xmlelement, "offline", [], []}]}]
|
||||
}),
|
||||
true
|
||||
end;
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end.
|
||||
|
||||
find_x_event([]) ->
|
||||
false;
|
||||
find_x_event([{xmlcdata, _} | Els]) ->
|
||||
find_x_event(Els);
|
||||
find_x_event([El | Els]) ->
|
||||
case xml:get_tag_attr_s("xmlns", El) of
|
||||
?NS_EVENT ->
|
||||
El;
|
||||
_ ->
|
||||
find_x_event(Els)
|
||||
end.
|
||||
|
||||
find_x_expire(_, []) ->
|
||||
never;
|
||||
find_x_expire(TimeStamp, [{xmlcdata, _} | Els]) ->
|
||||
find_x_expire(TimeStamp, Els);
|
||||
find_x_expire(TimeStamp, [El | Els]) ->
|
||||
case xml:get_tag_attr_s("xmlns", El) of
|
||||
?NS_EXPIRE ->
|
||||
case xml:get_tag_attr_s("seconds", El) of
|
||||
Val ->
|
||||
case catch list_to_integer(Val) of
|
||||
{'EXIT', _} ->
|
||||
never;
|
||||
Int when Int > 0 ->
|
||||
{MegaSecs, Secs, MicroSecs} = TimeStamp,
|
||||
S = MegaSecs * 1000000 + Secs + Int,
|
||||
MegaSecs1 = S div 1000000,
|
||||
Secs1 = S rem 1000000,
|
||||
{MegaSecs1, Secs1, MicroSecs};
|
||||
_ ->
|
||||
never
|
||||
end;
|
||||
_ ->
|
||||
never
|
||||
end;
|
||||
_ ->
|
||||
find_x_expire(TimeStamp, Els)
|
||||
end.
|
||||
|
||||
|
||||
pop_offline_messages(Ls, User) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
EUser = ejabberd_odbc:escape(LUser),
|
||||
case ejabberd_odbc:sql_query(
|
||||
["begin;"
|
||||
"select * from spool where username='", EUser, "';"
|
||||
"delete from spool where username='", EUser, "';"
|
||||
"commit"]) of
|
||||
{selected, ["username","xml"], Rs} ->
|
||||
Ls ++ lists:flatmap(
|
||||
fun({_, XML}) ->
|
||||
case xml_stream:parse_element(XML) of
|
||||
{error, _Reason} ->
|
||||
[];
|
||||
El ->
|
||||
To = jlib:string_to_jid(
|
||||
xml:get_tag_attr_s("to", El)),
|
||||
From = jlib:string_to_jid(
|
||||
xml:get_tag_attr_s("from", El)),
|
||||
if
|
||||
(To /= error) and
|
||||
(From /= error) ->
|
||||
[{route, From, To, El}];
|
||||
true ->
|
||||
[]
|
||||
end
|
||||
end
|
||||
end, Rs);
|
||||
_ ->
|
||||
Ls
|
||||
end.
|
||||
|
||||
|
||||
remove_user(User) ->
|
||||
LUser = jlib:nodeprep(User),
|
||||
Username = ejabberd_odbc:escape(LUser),
|
||||
ejabberd_odbc:sql_query(
|
||||
["delete from spool where username='", Username, "'"]).
|
||||
|
123
src/odbc/ejabberd_odbc.erl
Normal file
123
src/odbc/ejabberd_odbc.erl
Normal file
@ -0,0 +1,123 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : ejabberd_odbc.erl
|
||||
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Purpose : Serve ODBC connection
|
||||
%%% Created : 8 Dec 2004 by Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Id : $Id$
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(ejabberd_odbc).
|
||||
-author('alexey@sevcom.net').
|
||||
-vsn('$Revision$ ').
|
||||
|
||||
-behaviour(gen_server).
|
||||
|
||||
%% External exports
|
||||
-export([start/0, start_link/0,
|
||||
sql_query/1,
|
||||
escape/1]).
|
||||
|
||||
%% gen_server callbacks
|
||||
-export([init/1,
|
||||
handle_call/3,
|
||||
handle_cast/2,
|
||||
code_change/3,
|
||||
handle_info/2,
|
||||
terminate/2]).
|
||||
|
||||
-record(state, {odbc_ref}).
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% API
|
||||
%%%----------------------------------------------------------------------
|
||||
start() ->
|
||||
gen_server:start({local, ejabberd_odbc}, ejabberd_odbc, [], []).
|
||||
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ejabberd_odbc}, ejabberd_odbc, [], []).
|
||||
|
||||
sql_query(Query) ->
|
||||
gen_server:call(ejabberd_odbc, {sql_query, Query}, 60000).
|
||||
|
||||
escape(S) ->
|
||||
[case C of
|
||||
$\0 -> "\\0";
|
||||
$\n -> "\\n";
|
||||
$\t -> "\\t";
|
||||
$\b -> "\\b";
|
||||
$\r -> "\\r";
|
||||
$' -> "\\'";
|
||||
$" -> "\\\"";
|
||||
$% -> "\\%";
|
||||
$_ -> "\\_";
|
||||
$\\ -> "\\\\";
|
||||
_ -> C
|
||||
end || C <- S].
|
||||
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Callback functions from gen_server
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: init/1
|
||||
%% Returns: {ok, State} |
|
||||
%% {ok, State, Timeout} |
|
||||
%% ignore |
|
||||
%% {stop, Reason}
|
||||
%%----------------------------------------------------------------------
|
||||
init([]) ->
|
||||
{ok, Ref} = odbc:connect("DSN=ejabberd;UID=ejabberd;PWD=ejabberd",
|
||||
[{scrollable_cursors, off}]),
|
||||
{ok, #state{odbc_ref = Ref}}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: handle_call/3
|
||||
%% Returns: {reply, Reply, State} |
|
||||
%% {reply, Reply, State, Timeout} |
|
||||
%% {noreply, State} |
|
||||
%% {noreply, State, Timeout} |
|
||||
%% {stop, Reason, Reply, State} | (terminate/2 is called)
|
||||
%% {stop, Reason, State} (terminate/2 is called)
|
||||
%%----------------------------------------------------------------------
|
||||
handle_call({sql_query, Query}, _From, State) ->
|
||||
Reply = odbc:sql_query(State#state.odbc_ref, Query),
|
||||
{reply, Reply, State};
|
||||
handle_call(_Request, _From, State) ->
|
||||
Reply = ok,
|
||||
{reply, Reply, State}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: handle_cast/2
|
||||
%% Returns: {noreply, State} |
|
||||
%% {noreply, State, Timeout} |
|
||||
%% {stop, Reason, State} (terminate/2 is called)
|
||||
%%----------------------------------------------------------------------
|
||||
handle_cast(_Msg, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: handle_info/2
|
||||
%% Returns: {noreply, State} |
|
||||
%% {noreply, State, Timeout} |
|
||||
%% {stop, Reason, State} (terminate/2 is called)
|
||||
%%----------------------------------------------------------------------
|
||||
handle_info(_Info, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: terminate/2
|
||||
%% Purpose: Shutdown the server
|
||||
%% Returns: any (ignored by gen_server)
|
||||
%%----------------------------------------------------------------------
|
||||
terminate(_Reason, _State) ->
|
||||
ok.
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Internal functions
|
||||
%%%----------------------------------------------------------------------
|
||||
|
89
src/odbc/pg.sql
Normal file
89
src/odbc/pg.sql
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
|
||||
CREATE TABLE users (
|
||||
username text NOT NULL,
|
||||
"password" text NOT NULL
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE last (
|
||||
username text NOT NULL,
|
||||
seconds text NOT NULL,
|
||||
state text
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE rosterusers (
|
||||
username text NOT NULL,
|
||||
jid text NOT NULL,
|
||||
nick text,
|
||||
subscription character(1) NOT NULL,
|
||||
ask character(1) NOT NULL,
|
||||
server character(1) NOT NULL,
|
||||
subscribe text,
|
||||
"type" text
|
||||
);
|
||||
|
||||
|
||||
|
||||
CREATE TABLE rostergroups (
|
||||
username text NOT NULL,
|
||||
jid text NOT NULL,
|
||||
grp text NOT NULL
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE spool (
|
||||
username text NOT NULL,
|
||||
xml text
|
||||
);
|
||||
|
||||
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user