aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlexey Shchepin <alexey@process-one.net>2004-08-08 19:07:55 +0000
committerAlexey Shchepin <alexey@process-one.net>2004-08-08 19:07:55 +0000
commit357554265e4c86c5cd0dc3b6ae2f69f20c85786b (patch)
tree41219e7fbcccd2f24ca040c8fad8237bdc6e2e8b /src
parent* src/aclocal.m4: Updated to check for openssl library (thanks to (diff)
* src/ejabberd_c2s.erl: Use resend_offline_messages_hook to fetch
offline messages * src/mod_offline.erl: Likewise * src/mod_offline.erl: Added table locking in remove_old_messages/1 * src/ejabberd_sm.erl: Use offline_message_hook to store offline messages * src/mod_offline.erl: Likewise * src/ejabberd_hooks.erl: Hooks support * src/ejabberd_sup.erl: Added ejabberd_hooks * doc/guide.tex: Updated * src/ejabberd.cfg.example: Updated * src/ejabberd_c2s.erl: Changed TLS options (thanks to Sergei Golovan) SVN Revision: 255
Diffstat (limited to 'src')
-rw-r--r--src/ejabberd.cfg.example9
-rw-r--r--src/ejabberd_c2s.erl12
-rw-r--r--src/ejabberd_hooks.erl183
-rw-r--r--src/ejabberd_sm.erl20
-rw-r--r--src/ejabberd_sup.erl78
-rw-r--r--src/mod_offline.erl43
6 files changed, 280 insertions, 65 deletions
diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example
index 405f4a2b2..82e1cc43c 100644
--- a/src/ejabberd.cfg.example
+++ b/src/ejabberd.cfg.example
@@ -91,8 +91,13 @@
% Listened ports:
{listen,
- [{5222, ejabberd_c2s, [{access, c2s}, {shaper, c2s_shaper}]},
- {5223, ejabberd_c2s, [{access, c2s}, ssl, {certfile, "./ssl.pem"}]},
+ [{5222, ejabberd_c2s, [{access, c2s}, {shaper, c2s_shaper},
+ starttls, {certfile, "./ssl.pem"}]},
+ {5223, ejabberd_c2s, [{access, c2s},
+ tls, {certfile, "./ssl.pem"}]},
+ % Use these two lines instead if TLS support is not compiled
+ %{5222, ejabberd_c2s, [{access, c2s}, {shaper, c2s_shaper}]},
+ %{5223, ejabberd_c2s, [{access, c2s}, ssl, {certfile, "./ssl.pem"}]},
{5269, ejabberd_s2s_in, [{shaper, s2s_shaper}]},
{5280, ejabberd_http, [http_poll, web_admin]},
{8888, ejabberd_service, [{access, all},
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index b5b3128da..844e7bcfb 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -80,8 +80,6 @@
-define(INVALID_NS_ERR,
xml:element_to_string(?SERR_INVALID_NAMESPACE)).
-%-define(INVALID_XML_ERR,
-% "<stream:error code='400'>Invalid XML</stream:error>").
-define(INVALID_XML_ERR,
xml:element_to_string(?SERR_XML_NOT_WELL_FORMED)).
@@ -118,8 +116,9 @@ init([{SockMod, Socket}, Opts]) ->
{value, {_, S}} -> S;
_ -> none
end,
- TLS = lists:member(tls, Opts),
- TLSEnabled = lists:member(tls_from_start, Opts),
+ StartTLS = lists:member(starttls, Opts),
+ TLSEnabled = lists:member(tls, Opts),
+ TLS = StartTLS orelse TLSEnabled,
TLSOpts = lists:filter(fun({certfile, _}) -> true;
(_) -> false
end, Opts),
@@ -1387,9 +1386,8 @@ process_privacy_iq(From, To,
resend_offline_messages(StateData) ->
- case catch mod_offline:pop_offline_messages(StateData#state.user) of
- {'EXIT', _Reason} ->
- ok;
+ case ejabberd_hooks:run_fold(resend_offline_messages_hook, [],
+ [StateData#state.user]) of
Rs when list(Rs) ->
lists:foreach(
fun({route, From, To, {xmlelement, Name, Attrs, Els}}) ->
diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl
new file mode 100644
index 000000000..c00035b41
--- /dev/null
+++ b/src/ejabberd_hooks.erl
@@ -0,0 +1,183 @@
+%%%----------------------------------------------------------------------
+%%% File : ejabberd_hooks.erl
+%%% Author : Alexey Shchepin <alexey@sevcom.net>
+%%% Purpose : Manage hooks
+%%% Created : 8 Aug 2004 by Alexey Shchepin <alexey@sevcom.net>
+%%% Id : $Id$
+%%%----------------------------------------------------------------------
+
+-module(ejabberd_hooks).
+-author('alexey@sevcom.net').
+
+-behaviour(gen_server).
+
+%% External exports
+-export([start_link/0,
+ add/4,
+ delete/4,
+ run/2,
+ run_fold/3]).
+
+%% gen_server callbacks
+-export([init/1,
+ handle_call/3,
+ handle_cast/2,
+ code_change/3,
+ handle_info/2,
+ terminate/2]).
+
+-include("ejabberd.hrl").
+
+-record(state, {}).
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+start_link() ->
+ gen_server:start_link({local, ejabberd_hooks}, ejabberd_hooks, [], []).
+
+add(Hook, Module, Function, Seq) ->
+ gen_server:call(ejabberd_hooks, {add, Hook, Module, Function, Seq}).
+
+delete(Hook, Module, Function, Seq) ->
+ gen_server:call(ejabberd_hooks, {delete, Hook, Module, Function, Seq}).
+
+run(Hook, Args) ->
+ case ets:lookup(hooks, Hook) of
+ [{_, Ls}] ->
+ run1(Ls, Hook, Args);
+ [] ->
+ ok
+ end.
+
+run_fold(Hook, Val, Args) ->
+ case ets:lookup(hooks, Hook) of
+ [{_, Ls}] ->
+ run_fold1(Ls, Hook, Val, Args);
+ [] ->
+ ok
+ end.
+
+%%%----------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%----------------------------------------------------------------------
+init([]) ->
+ ets:new(hooks, [named_table]),
+ {ok, #state{}}.
+
+%%----------------------------------------------------------------------
+%% 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({add, Hook, Module, Function, Seq}, From, State) ->
+ Reply = case ets:lookup(hooks, Hook) of
+ [{_, Ls}] ->
+ El = {Seq, Module, Function},
+ case lists:member(El, Ls) of
+ true ->
+ ok;
+ false ->
+ NewLs = lists:merge(Ls, [El]),
+ ets:insert(hooks, {Hook, NewLs}),
+ ok
+ end;
+ [] ->
+ NewLs = [{Seq, Module, Function}],
+ ets:insert(hooks, {Hook, NewLs}),
+ ok
+ end,
+ {reply, Reply, State};
+handle_call({delete, Hook, Module, Function, Seq}, From, State) ->
+ Reply = case ets:lookup(hooks, Hook) of
+ [{_, Ls}] ->
+ NewLs = lists:delete({Seq, Module, Function}, Ls),
+ ets:insert(hooks, {Hook, NewLs}),
+ ok;
+ [] ->
+ ok
+ end,
+ {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}.
+
+%%----------------------------------------------------------------------
+%% 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.
+
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+
+run1([], Hook, Args) ->
+ ok;
+run1([{_Seq, Module, Function} | Ls], Hook, Args) ->
+ case catch apply(Module, Function, Args) of
+ {'EXIT', Reason} ->
+ ?ERROR_MSG("~p~nrunning hook: ~p",
+ [Reason, {Hook, Args}]),
+ run1(Ls, Hook, Args);
+ stop ->
+ ok;
+ _ ->
+ run1(Ls, Hook, Args)
+ end.
+
+
+run_fold1([], Hook, Val, Args) ->
+ Val;
+run_fold1([{_Seq, Module, Function} | Ls], Hook, Val, Args) ->
+ case catch apply(Module, Function, [Val | Args]) of
+ {'EXIT', Reason} ->
+ ?ERROR_MSG("~p~nrunning hook: ~p",
+ [Reason, {Hook, Args}]),
+ run_fold1(Ls, Hook, Val, Args);
+ stop ->
+ stopped;
+ {stop, NewVal} ->
+ NewVal;
+ NewVal ->
+ run_fold1(Ls, Hook, NewVal, Args)
+ end.
+
+
+
diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl
index 882c61e0e..d4a972518 100644
--- a/src/ejabberd_sm.erl
+++ b/src/ejabberd_sm.erl
@@ -11,6 +11,7 @@
-vsn('$Revision$ ').
-export([start_link/0, init/0, open_session/2, close_session/2,
+ bounce_offline_message/3,
get_user_resources/1,
set_presence/3,
unset_presence/3,
@@ -44,6 +45,8 @@ init() ->
mnesia:add_table_index(presence, user),
mnesia:subscribe(system),
ets:new(sm_iqtable, [named_table]),
+ ejabberd_hooks:add(offline_message_hook,
+ ejabberd_sm, bounce_offline_message, 100),
loop().
loop() ->
@@ -263,18 +266,11 @@ route_message(From, To, Packet) ->
_ ->
case ejabberd_auth:is_user_exists(LUser) of
true ->
- case catch mod_offline:store_packet(
- From, To, Packet) of
- {'EXIT', _} ->
- Err = jlib:make_error_reply(
- Packet, ?ERR_SERVICE_UNAVAILABLE),
- ejabberd_router:route(To, From, Err);
- _ ->
- ok
- end;
+ ejabberd_hooks:run(offline_message_hook,
+ [From, To, Packet]);
_ ->
Err = jlib:make_error_reply(
- Packet, ?ERR_ITEM_NOT_FOUND),
+ Packet, ?ERR_SERVICE_UNAVAILABLE),
ejabberd_router:route(To, From, Err)
end
end;
@@ -291,6 +287,10 @@ route_message(From, To, Packet) ->
end
end.
+bounce_offline_message(From, To, Packet) ->
+ Err = jlib:make_error_reply(Packet, ?ERR_SERVICE_UNAVAILABLE),
+ ejabberd_router:route(To, From, Err),
+ stop.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/src/ejabberd_sup.erl b/src/ejabberd_sup.erl
index bda9b79a1..9a2cc74d5 100644
--- a/src/ejabberd_sup.erl
+++ b/src/ejabberd_sup.erl
@@ -19,36 +19,48 @@ start_link() ->
init([]) ->
- Router = {ejabberd_router,
- {ejabberd_router, start_link, []},
- permanent,
- brutal_kill,
- worker,
- [ejabberd_router]},
- SM = {ejabberd_sm,
- {ejabberd_sm, start_link, []},
- permanent,
- brutal_kill,
- worker,
- [ejabberd_sm]},
- S2S = {ejabberd_s2s,
- {ejabberd_s2s, start_link, []},
- permanent,
- brutal_kill,
- worker,
- [ejabberd_s2s]},
- Local = {ejabberd_local,
- {ejabberd_local, start_link, []},
- permanent,
- brutal_kill,
- worker,
- [ejabberd_local]},
- Listener = {ejabberd_listener,
- {ejabberd_listener, start_link, []},
- permanent,
- infinity,
- supervisor,
- [ejabberd_listener]},
+ Hooks =
+ {ejabberd_hooks,
+ {ejabberd_hooks, start_link, []},
+ permanent,
+ brutal_kill,
+ worker,
+ [ejabberd_hooks]},
+ Router =
+ {ejabberd_router,
+ {ejabberd_router, start_link, []},
+ permanent,
+ brutal_kill,
+ worker,
+ [ejabberd_router]},
+ SM =
+ {ejabberd_sm,
+ {ejabberd_sm, start_link, []},
+ permanent,
+ brutal_kill,
+ worker,
+ [ejabberd_sm]},
+ S2S =
+ {ejabberd_s2s,
+ {ejabberd_s2s, start_link, []},
+ permanent,
+ brutal_kill,
+ worker,
+ [ejabberd_s2s]},
+ Local =
+ {ejabberd_local,
+ {ejabberd_local, start_link, []},
+ permanent,
+ brutal_kill,
+ worker,
+ [ejabberd_local]},
+ Listener =
+ {ejabberd_listener,
+ {ejabberd_listener, start_link, []},
+ permanent,
+ infinity,
+ supervisor,
+ [ejabberd_listener]},
StringPrep =
{stringprep,
{stringprep, start_link, []},
@@ -112,7 +124,11 @@ init([]) ->
supervisor,
[ejabberd_tmp_sup]},
{ok, {{one_for_one, 10, 1},
- [Router, SM, S2S, Local,
+ [Hooks,
+ Router,
+ SM,
+ S2S,
+ Local,
StringPrep,
C2SSupervisor,
S2SInSupervisor,
diff --git a/src/mod_offline.erl b/src/mod_offline.erl
index 7af72442b..22e9b85ee 100644
--- a/src/mod_offline.erl
+++ b/src/mod_offline.erl
@@ -16,7 +16,7 @@
stop/0,
store_packet/3,
resend_offline_messages/1,
- pop_offline_messages/1,
+ pop_offline_messages/2,
remove_old_messages/1,
remove_user/1]).
@@ -31,6 +31,10 @@ start(_) ->
[{disc_only_copies, [node()]},
{type, bag},
{attributes, record_info(fields, offline_msg)}]),
+ ejabberd_hooks:add(offline_message_hook,
+ ?MODULE, store_packet, 50),
+ ejabberd_hooks:add(resend_offline_messages_hook,
+ ?MODULE, pop_offline_messages, 50),
register(?PROCNAME, spawn(?MODULE, init, [])).
init() ->
@@ -61,23 +65,31 @@ receive_all(Msgs) ->
stop() ->
+ ejabberd_hooks:delete(offline_message_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) ->
- true = is_process_alive(whereis(?PROCNAME)),
Type = xml:get_tag_attr_s("type", Packet),
- true = Type /= "error" andalso Type /= "groupchat",
- case check_event(From, To, Packet) of
+ if
+ (Type /= "error") and (Type /= "groupchat") ->
+ case check_event(From, To, Packet) of
+ true ->
+ #jid{luser = LUser} = To,
+ TimeStamp = now(),
+ ?PROCNAME ! #offline_msg{user = LUser,
+ timestamp = TimeStamp,
+ from = From,
+ to = To,
+ packet = Packet},
+ stop;
+ _ ->
+ ok
+ end;
true ->
- #jid{luser = LUser} = To,
- TimeStamp = now(),
- ?PROCNAME ! #offline_msg{user = LUser,
- timestamp = TimeStamp,
- from = From,
- to = To,
- packet = Packet};
- _ ->
ok
end.
@@ -154,7 +166,7 @@ resend_offline_messages(User) ->
ok
end.
-pop_offline_messages(User) ->
+pop_offline_messages(Ls, User) ->
LUser = jlib:nodeprep(User),
F = fun() ->
Rs = mnesia:wread({offline_msg, LUser}),
@@ -175,9 +187,9 @@ pop_offline_messages(User) ->
calendar:now_to_universal_time(
R#offline_msg.timestamp))]}}
end,
- lists:keysort(#offline_msg.timestamp, Rs));
+ Ls ++ lists:keysort(#offline_msg.timestamp, Rs));
_ ->
- []
+ Ls
end.
remove_old_messages(Days) ->
@@ -187,6 +199,7 @@ remove_old_messages(Days) ->
Secs1 = S rem 1000000,
TimeStamp = {MegaSecs1, Secs1, 0},
F = fun() ->
+ mnesia:write_lock_table(offline_msg),
mnesia:foldl(
fun(#offline_msg{timestamp = TS} = Rec, _Acc)
when TS < TimeStamp ->