aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog23
-rw-r--r--doc/guide.html16
-rw-r--r--doc/guide.tex18
-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
9 files changed, 327 insertions, 75 deletions
diff --git a/ChangeLog b/ChangeLog
index 05cd2c438..e6043d3b9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2004-08-08 Alexey Shchepin <alexey@sevcom.net>
+
+ * 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)
+
2004-08-05 Alexey Shchepin <alexey@sevcom.net>
* src/aclocal.m4: Updated to check for openssl library (thanks to
diff --git a/doc/guide.html b/doc/guide.html
index 2db534258..851bb0384 100644
--- a/doc/guide.html
+++ b/doc/guide.html
@@ -142,7 +142,7 @@ Works on most of popular platforms: *nix (tested on Linux, FreeBSD and
The misfeatures of <TT>ejabberd</TT> are:
<UL><LI>
No support for virtual domains
-<LI>No support for STARTTLS
+<LI>No support for authentification and STARTTLS in S2S connections
</UL>
<!--TOC section Installation-->
@@ -164,7 +164,8 @@ To compile <TT>ejabberd</TT>, you will need the following packages:
GNU Make;
<LI>GCC;
<LI>libexpat 1.95 or later;
-<LI>Erlang/OTP R8B or later.
+<LI>Erlang/OTP R8B or later;
+<LI>OpenSSL 0.9.6 or later (optional).
</UL>
<!--TOC subsubsection Windows-->
@@ -473,8 +474,15 @@ The following options are defined:
<DT><B><TT>{ip, IPAddress}</TT></B><DD> This option specifies which network interface to
listen on. For example <CODE>{ip, {192, 168, 1, 1}}</CODE>.
<DT><B><TT>inet6</TT></B><DD> Set up the socket for IPv6.
+ <DT><B><TT>tls</TT></B><DD> This option specifies that STARTTLS extension is available on
+ connections to this port. You should also set ``<CODE>certfile</CODE>'' option.
+ <DT><B><TT>tls_from_start</TT></B><DD> Among with <TT>tls</TT> this option specifies that
+ traffic on this port will be encrypted using SSL immediately after
+ connecting.
<DT><B><TT>ssl</TT></B><DD> This option specifies that traffic on this port will be
- encrypted using SSL. You should also set ``<CODE>certfile</CODE>'' option.
+ encrypted using SSL. You should also set ``<CODE>certfile</CODE>'' option. It
+ is recommended to use <TT>tls</TT> and <TT>tls_from_start</TT> options
+ instead.
<DT><B><TT>{certfile, Path}</TT></B><DD> Path to a file containing the SSL certificate.
</DL>
<DT><B><TT>ejabberd_s2s_in</TT></B><DD> This module serves incoming S2S connections.
@@ -495,7 +503,7 @@ The following additional options are defined for <TT>ejabberd_service</TT>
<BR>
The following options are defined:
<DL COMPACT=compact><DT>
- <B><TT>http_poll</TT></B><DD> This option enables <A HREF="http://www.jabber.org/jeps/jep-0025.html">HTTP Polling</A> .
+ <B><TT>http_poll</TT></B><DD> This option enables <A HREF="http://www.jabber.org/jeps/jep-0025.html">HTTP Polling</A>
support. It is available then at <CODE>http://server:port/http-poll/</CODE>.<BR>
<BR>
<DT><B><TT>web_admin</TT></B><DD> This option enables web-based interface for <TT>ejabberd</TT>
diff --git a/doc/guide.tex b/doc/guide.tex
index 732aec45f..dd78dbb98 100644
--- a/doc/guide.tex
+++ b/doc/guide.tex
@@ -126,7 +126,7 @@ The main features of \ejabberd{} are:
The misfeatures of \ejabberd{} are:
\begin{itemize}
\item No support for virtual domains
-\item No support for STARTTLS
+\item No support for authentification and STARTTLS in S2S connections
\end{itemize}
@@ -144,7 +144,8 @@ To compile \ejabberd{}, you will need the following packages:
\item GNU Make;
\item GCC;
\item libexpat 1.95 or later;
-\item Erlang/OTP R8B or later.
+\item Erlang/OTP R8B or later;
+\item OpenSSL 0.9.6 or later (optional).
\end{itemize}
\subsubsection{Windows}
@@ -285,8 +286,6 @@ But in this case \ejabberd{} can start to work slower.
\subsection{Initial Configuration}
\label{sec:initconfig}
-%\verbatiminput{../src/ejabberd.cfg}
-
The configuration file is initially loaded the first time \ejabberd{} is
executed, when it is parsed and stored in a database. Subsequently the
configuration is loaded from the database and any commands in the configuration
@@ -477,8 +476,15 @@ Currently these modules are implemented:
\titem{\{ip, IPAddress\}} This option specifies which network interface to
listen on. For example \verb|{ip, {192, 168, 1, 1}}|.
\titem{inet6} Set up the socket for IPv6.
+ \titem{starttls} This option specifies that STARTTLS extension is available
+ on connections to this port. You should also set ``\verb|certfile|''
+ option.
+ \titem{tls} This option specifies that traffic on this port will be
+ encrypted using SSL immediately after connecting. You should also set
+ ``\verb|certfile|'' option.
\titem{ssl} This option specifies that traffic on this port will be
- encrypted using SSL. You should also set ``\verb|certfile|'' option.
+ encrypted using SSL. You should also set ``\verb|certfile|'' option. It
+ is recommended to use \term{tls} option instead.
\titem{\{certfile, Path\}} Path to a file containing the SSL certificate.
\end{description}
\titem{ejabberd\_s2s\_in} This module serves incoming S2S connections.
@@ -499,7 +505,7 @@ Currently these modules are implemented:
The following options are defined:
\begin{description}
- \titem{http\_poll} This option enables \tjepref{0025}{HTTP Polling} .
+ \titem{http\_poll} This option enables \tjepref{0025}{HTTP Polling}
support. It is available then at \verb|http://server:port/http-poll/|.
\titem{web\_admin} This option enables web-based interface for \ejabberd{}
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 ->