* src/ejabberd_c2s.erl: Bugfix in resend_offline_messages/1

* src/mod_announce.erl: New module to manage announce messages
(thanks to Sergei Golovan)

* src/ejabberd_local.erl: Moved processing of announce messages to
mod_announce (thanks to Sergei Golovan)

* src/ejabberd_c2s.erl: Added several hooks

* src/ejabberd_hooks.erl: Fixed run_fold (thanks to Sergei
Golovan)

* src/ejabberd.cfg.example: Updated (thanks to Sergei Golovan)

* doc/guide.tex: Updated (thanks to Sergei Golovan)

SVN Revision: 256
This commit is contained in:
Alexey Shchepin 2004-08-12 22:34:19 +00:00
parent 357554265e
commit d77a936b32
9 changed files with 342 additions and 76 deletions

View File

@ -1,3 +1,22 @@
2004-08-12 Alexey Shchepin <alexey@sevcom.net>
* src/ejabberd_c2s.erl: Bugfix in resend_offline_messages/1
* src/mod_announce.erl: New module to manage announce messages
(thanks to Sergei Golovan)
* src/ejabberd_local.erl: Moved processing of announce messages to
mod_announce (thanks to Sergei Golovan)
* src/ejabberd_c2s.erl: Added several hooks
* src/ejabberd_hooks.erl: Fixed run_fold (thanks to Sergei
Golovan)
* src/ejabberd.cfg.example: Updated (thanks to Sergei Golovan)
* doc/guide.tex: Updated (thanks to Sergei Golovan)
2004-08-08 Alexey Shchepin <alexey@sevcom.net>
* src/ejabberd_c2s.erl: Use resend_offline_messages_hook to fetch

View File

@ -85,24 +85,25 @@
<A HREF="#htoc30">A.1.1&nbsp;&nbsp;Option <TT>iqdisc</TT></A>
<LI><A HREF="#htoc31">A.1.2&nbsp;&nbsp;Option <TT>host</TT></A>
</UL>
<LI><A HREF="#htoc32">A.2&nbsp;&nbsp;<TT>mod_configure</TT></A>
<LI><A HREF="#htoc33">A.3&nbsp;&nbsp;<TT>mod_disco</TT></A>
<LI><A HREF="#htoc34">A.4&nbsp;&nbsp;<TT>mod_echo</TT></A>
<LI><A HREF="#htoc35">A.5&nbsp;&nbsp;<TT>mod_irc</TT></A>
<LI><A HREF="#htoc36">A.6&nbsp;&nbsp;<TT>mod_last</TT></A>
<LI><A HREF="#htoc37">A.7&nbsp;&nbsp;<TT>mod_muc</TT></A>
<LI><A HREF="#htoc38">A.8&nbsp;&nbsp;<TT>mod_offline</TT></A>
<LI><A HREF="#htoc39">A.9&nbsp;&nbsp;<TT>mod_privacy</TT></A>
<LI><A HREF="#htoc40">A.10&nbsp;&nbsp;<TT>mod_private</TT></A>
<LI><A HREF="#htoc41">A.11&nbsp;&nbsp;<TT>mod_pubsub</TT></A>
<LI><A HREF="#htoc42">A.12&nbsp;&nbsp;<TT>mod_register</TT></A>
<LI><A HREF="#htoc43">A.13&nbsp;&nbsp;<TT>mod_roster</TT></A>
<LI><A HREF="#htoc44">A.14&nbsp;&nbsp;<TT>mod_stats</TT></A>
<LI><A HREF="#htoc45">A.15&nbsp;&nbsp;<TT>mod_time</TT></A>
<LI><A HREF="#htoc46">A.16&nbsp;&nbsp;<TT>mod_vcard</TT></A>
<LI><A HREF="#htoc47">A.17&nbsp;&nbsp;<TT>mod_version</TT></A>
<LI><A HREF="#htoc32">A.2&nbsp;&nbsp;<TT>mod_announce</TT></A>
<LI><A HREF="#htoc33">A.3&nbsp;&nbsp;<TT>mod_configure</TT></A>
<LI><A HREF="#htoc34">A.4&nbsp;&nbsp;<TT>mod_disco</TT></A>
<LI><A HREF="#htoc35">A.5&nbsp;&nbsp;<TT>mod_echo</TT></A>
<LI><A HREF="#htoc36">A.6&nbsp;&nbsp;<TT>mod_irc</TT></A>
<LI><A HREF="#htoc37">A.7&nbsp;&nbsp;<TT>mod_last</TT></A>
<LI><A HREF="#htoc38">A.8&nbsp;&nbsp;<TT>mod_muc</TT></A>
<LI><A HREF="#htoc39">A.9&nbsp;&nbsp;<TT>mod_offline</TT></A>
<LI><A HREF="#htoc40">A.10&nbsp;&nbsp;<TT>mod_privacy</TT></A>
<LI><A HREF="#htoc41">A.11&nbsp;&nbsp;<TT>mod_private</TT></A>
<LI><A HREF="#htoc42">A.12&nbsp;&nbsp;<TT>mod_pubsub</TT></A>
<LI><A HREF="#htoc43">A.13&nbsp;&nbsp;<TT>mod_register</TT></A>
<LI><A HREF="#htoc44">A.14&nbsp;&nbsp;<TT>mod_roster</TT></A>
<LI><A HREF="#htoc45">A.15&nbsp;&nbsp;<TT>mod_stats</TT></A>
<LI><A HREF="#htoc46">A.16&nbsp;&nbsp;<TT>mod_time</TT></A>
<LI><A HREF="#htoc47">A.17&nbsp;&nbsp;<TT>mod_vcard</TT></A>
<LI><A HREF="#htoc48">A.18&nbsp;&nbsp;<TT>mod_version</TT></A>
</UL>
<LI><A HREF="#htoc48">B&nbsp;&nbsp;I18n/L10n</A>
<LI><A HREF="#htoc49">B&nbsp;&nbsp;I18n/L10n</A>
</UL>
<!--TOC section Introduction-->
@ -474,15 +475,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>starttls</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</TT></B><DD> This option specifies that traffic on this port will be
encrypted using SSL immediately after connecting. You should also set
``<CODE>certfile</CODE>'' option.
<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. It
is recommended to use <TT>tls</TT> and <TT>tls_from_start</TT> options
instead.
is recommended to use <TT>tls</TT> option 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.
@ -818,9 +819,33 @@ Example:
...
]}.
</PRE>
<!--TOC subsection <TT>mod_announce</TT>-->
<H3><A NAME="htoc32">A.2</A>&nbsp;&nbsp;<TT>mod_announce</TT></H3><!--SEC END -->
<A NAME="sec:modannounce"></A>
This module adds support for broadcast announce messages and MOTD.<BR>
<BR>
Options:
<DL COMPACT=compact><DT>
<B><TT>access</TT></B><DD> Specifies who is allowed to send announce messages
and set MOTD (default value is <TT>none</TT>).
</DL>
Example:
<PRE>
% Only admins can send announcement messages:
{access, announce, [{allow, admin}]}.
{modules,
[
...
{mod_announce, [{access, announce}]},
...
]}.
</PRE>
<!--TOC subsection <TT>mod_configure</TT>-->
<H3><A NAME="htoc32">A.2</A>&nbsp;&nbsp;<TT>mod_configure</TT></H3><!--SEC END -->
<H3><A NAME="htoc33">A.3</A>&nbsp;&nbsp;<TT>mod_configure</TT></H3><!--SEC END -->
<A NAME="sec:modconfigure"></A>
Options:
@ -830,7 +855,7 @@ discipline (see&nbsp;<A HREF="#sec:modiqdiscoption">A.1.1</A>).
</DL>
<!--TOC subsection <TT>mod_disco</TT>-->
<H3><A NAME="htoc33">A.3</A>&nbsp;&nbsp;<TT>mod_disco</TT></H3><!--SEC END -->
<H3><A NAME="htoc34">A.4</A>&nbsp;&nbsp;<TT>mod_disco</TT></H3><!--SEC END -->
<A NAME="sec:moddisco"></A>
This module adds support for <A HREF="http://www.jabber.org/jeps/jep-0030.html">JEP-0030</A> (Service Discovery).<BR>
@ -855,7 +880,7 @@ Example:
</PRE>
<!--TOC subsection <TT>mod_echo</TT>-->
<H3><A NAME="htoc34">A.4</A>&nbsp;&nbsp;<TT>mod_echo</TT></H3><!--SEC END -->
<H3><A NAME="htoc35">A.5</A>&nbsp;&nbsp;<TT>mod_echo</TT></H3><!--SEC END -->
<A NAME="sec:modecho"></A>
This module acts as a service and simply returns to sender any Jabber packet. Module may be
@ -869,7 +894,7 @@ then prefix <TT>echo.</TT> is added to main <TT>ejabberd</TT> hostname.
</DL>
<!--TOC subsection <TT>mod_irc</TT>-->
<H3><A NAME="htoc35">A.5</A>&nbsp;&nbsp;<TT>mod_irc</TT></H3><!--SEC END -->
<H3><A NAME="htoc36">A.6</A>&nbsp;&nbsp;<TT>mod_irc</TT></H3><!--SEC END -->
<A NAME="sec:modirc"></A>
This module implements IRC transport.<BR>
@ -892,7 +917,7 @@ Example:
</PRE>
<!--TOC subsection <TT>mod_last</TT>-->
<H3><A NAME="htoc36">A.6</A>&nbsp;&nbsp;<TT>mod_last</TT></H3><!--SEC END -->
<H3><A NAME="htoc37">A.7</A>&nbsp;&nbsp;<TT>mod_last</TT></H3><!--SEC END -->
<A NAME="sec:modlast"></A>
This module adds support for <A HREF="http://www.jabber.org/jeps/jep-0012.html">JEP-0012</A> (Last Activity)<BR>
@ -904,7 +929,7 @@ discipline (see&nbsp;<A HREF="#sec:modiqdiscoption">A.1.1</A>).
</DL>
<!--TOC subsection <TT>mod_muc</TT>-->
<H3><A NAME="htoc37">A.7</A>&nbsp;&nbsp;<TT>mod_muc</TT></H3><!--SEC END -->
<H3><A NAME="htoc38">A.8</A>&nbsp;&nbsp;<TT>mod_muc</TT></H3><!--SEC END -->
<A NAME="sec:modmuc"></A>
This module implements <A HREF="http://www.jabber.org/jeps/jep-0045.html">JEP-0045</A> (Multi-User Chat) service.<BR>
@ -939,14 +964,14 @@ Example:
</PRE>
<!--TOC subsection <TT>mod_offline</TT>-->
<H3><A NAME="htoc38">A.8</A>&nbsp;&nbsp;<TT>mod_offline</TT></H3><!--SEC END -->
<H3><A NAME="htoc39">A.9</A>&nbsp;&nbsp;<TT>mod_offline</TT></H3><!--SEC END -->
<A NAME="sec:modoffline"></A>
This module implements offline message storage.<BR>
<BR>
<!--TOC subsection <TT>mod_privacy</TT>-->
<H3><A NAME="htoc39">A.9</A>&nbsp;&nbsp;<TT>mod_privacy</TT></H3><!--SEC END -->
<H3><A NAME="htoc40">A.10</A>&nbsp;&nbsp;<TT>mod_privacy</TT></H3><!--SEC END -->
<A NAME="sec:modprivacy"></A>
This module implements Privacy Rules as defined in XMPP IM
@ -959,7 +984,7 @@ discipline (see&nbsp;<A HREF="#sec:modiqdiscoption">A.1.1</A>).
</DL>
<!--TOC subsection <TT>mod_private</TT>-->
<H3><A NAME="htoc40">A.10</A>&nbsp;&nbsp;<TT>mod_private</TT></H3><!--SEC END -->
<H3><A NAME="htoc41">A.11</A>&nbsp;&nbsp;<TT>mod_private</TT></H3><!--SEC END -->
<A NAME="sec:modprivate"></A>
This module adds support of <A HREF="http://www.jabber.org/jeps/jep-0049.html">JEP-0049</A> (Private XML Storage).<BR>
@ -971,7 +996,7 @@ discipline (see&nbsp;<A HREF="#sec:modiqdiscoption">A.1.1</A>).
</DL>
<!--TOC subsection <TT>mod_pubsub</TT>-->
<H3><A NAME="htoc41">A.11</A>&nbsp;&nbsp;<TT>mod_pubsub</TT></H3><!--SEC END -->
<H3><A NAME="htoc42">A.12</A>&nbsp;&nbsp;<TT>mod_pubsub</TT></H3><!--SEC END -->
<A NAME="sec:modpubsub"></A>
This module implements <A HREF="http://www.jabber.org/jeps/jep-0060.html">JEP-0060</A> (Publish-Subscribe Service).<BR>
@ -996,7 +1021,7 @@ Example:
</PRE>
<!--TOC subsection <TT>mod_register</TT>-->
<H3><A NAME="htoc42">A.12</A>&nbsp;&nbsp;<TT>mod_register</TT></H3><!--SEC END -->
<H3><A NAME="htoc43">A.13</A>&nbsp;&nbsp;<TT>mod_register</TT></H3><!--SEC END -->
<A NAME="sec:modregister"></A>
This module adds support for <A HREF="http://www.jabber.org/jeps/jep-0077.html">JEP-0077</A> (In-Band Registration).<BR>
@ -1029,7 +1054,7 @@ Example:
</PRE>
<!--TOC subsection <TT>mod_roster</TT>-->
<H3><A NAME="htoc43">A.13</A>&nbsp;&nbsp;<TT>mod_roster</TT></H3><!--SEC END -->
<H3><A NAME="htoc44">A.14</A>&nbsp;&nbsp;<TT>mod_roster</TT></H3><!--SEC END -->
<A NAME="sec:modroster"></A>
This module implements roster management.<BR>
@ -1041,7 +1066,7 @@ discipline (see&nbsp;<A HREF="#sec:modiqdiscoption">A.1.1</A>).
</DL>
<!--TOC subsection <TT>mod_stats</TT>-->
<H3><A NAME="htoc44">A.14</A>&nbsp;&nbsp;<TT>mod_stats</TT></H3><!--SEC END -->
<H3><A NAME="htoc45">A.15</A>&nbsp;&nbsp;<TT>mod_stats</TT></H3><!--SEC END -->
<A NAME="sec:modstats"></A>
This module adds support for <A HREF="http://www.jabber.org/jeps/jep-0039.html">JEP-0039</A> (Statistics Gathering).<BR>
@ -1055,7 +1080,7 @@ TBD about access.<BR>
<BR>
<!--TOC subsection <TT>mod_time</TT>-->
<H3><A NAME="htoc45">A.15</A>&nbsp;&nbsp;<TT>mod_time</TT></H3><!--SEC END -->
<H3><A NAME="htoc46">A.16</A>&nbsp;&nbsp;<TT>mod_time</TT></H3><!--SEC END -->
<A NAME="sec:modtime"></A>
This module answers UTC time on <TT>jabber:iq:time</TT> queries.<BR>
@ -1067,7 +1092,7 @@ discipline (see&nbsp;<A HREF="#sec:modiqdiscoption">A.1.1</A>).
</DL>
<!--TOC subsection <TT>mod_vcard</TT>-->
<H3><A NAME="htoc46">A.16</A>&nbsp;&nbsp;<TT>mod_vcard</TT></H3><!--SEC END -->
<H3><A NAME="htoc47">A.17</A>&nbsp;&nbsp;<TT>mod_vcard</TT></H3><!--SEC END -->
<A NAME="sec:modvcard"></A>
This module implements simple Jabber User Directory (based on user vCards)
@ -1095,7 +1120,7 @@ Example:
</PRE>
<!--TOC subsection <TT>mod_version</TT>-->
<H3><A NAME="htoc47">A.17</A>&nbsp;&nbsp;<TT>mod_version</TT></H3><!--SEC END -->
<H3><A NAME="htoc48">A.18</A>&nbsp;&nbsp;<TT>mod_version</TT></H3><!--SEC END -->
<A NAME="sec:modversion"></A>
This module answers <TT>ejabberd</TT> version on <TT>jabber:iq:version</TT> queries.<BR>
@ -1107,7 +1132,7 @@ discipline (see&nbsp;<A HREF="#sec:modiqdiscoption">A.1.1</A>).
</DL>
<!--TOC section I18n/L10n-->
<H2><A NAME="htoc48">B</A>&nbsp;&nbsp;I18n/L10n</H2><!--SEC END -->
<H2><A NAME="htoc49">B</A>&nbsp;&nbsp;I18n/L10n</H2><!--SEC END -->
<A NAME="sec:i18nl10n"></A>
All built-in modules support <TT>xml:lang</TT> attribute inside IQ queries.

View File

@ -34,6 +34,7 @@
\newcommand{\Jabber}{Jabber}
\newcommand{\module}[1]{\texttt{#1}}
\newcommand{\modannounce}{\module{mod\_announce}}
\newcommand{\modconfigure}{\module{mod\_configure}}
\newcommand{\moddisco}{\module{mod\_disco}}
\newcommand{\modirc}{\module{mod\_irc}}
@ -812,6 +813,31 @@ Example:
\end{verbatim}
\subsection{\modannounce{}}
\label{sec:modannounce}
This module adds support for broadcast announce messages and MOTD.
Options:
\begin{description}
\titem{access} Specifies who is allowed to send announce messages
and set MOTD (default value is \term{none}).
\end{description}
Example:
\begin{verbatim}
% Only admins can send announcement messages:
{access, announce, [{allow, admin}]}.
{modules,
[
...
{mod_announce, [{access, announce}]},
...
]}.
\end{verbatim}
\subsection{\modconfigure{}}
\label{sec:modconfigure}

View File

@ -51,7 +51,7 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) ->
AuthzId = xml:get_attr_s("authzid", KeyVals),
case ejabberd_auth:get_password(UserName) of
false ->
{error, "no-user"};
{error, "not-authorized"};
Passwd ->
Response = response(KeyVals, UserName, Passwd,
Nonce, AuthzId, "AUTHENTICATE"),
@ -66,7 +66,7 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) ->
username = UserName,
authzid = AuthzId}};
_ ->
{error, "bad-auth"}
{error, "not-authorized"}
end
end
end;

View File

@ -121,6 +121,7 @@
{mod_stats, []},
{mod_vcard, []},
{mod_offline, []},
{mod_announce, [{access, announce}]},
{mod_echo, [{host, "echo.localhost"}]},
{mod_private, []},
{mod_irc, []},

View File

@ -673,12 +673,17 @@ session_established({xmlstreamelement, El}, StateData) ->
process_privacy_iq(
FromJID, ToJID, IQ, StateData);
_ ->
ejabberd_hooks:run(
user_send_packet,
[FromJID, ToJID, NewEl]),
ejabberd_router:route(
FromJID, ToJID, NewEl),
StateData
end
end;
"message" ->
ejabberd_hooks:run(user_send_packet,
[FromJID, ToJID, NewEl]),
ejabberd_router:route(FromJID, ToJID, NewEl),
StateData;
_ ->
@ -882,8 +887,11 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
Attrs2 = jlib:replace_from_to_attrs(jlib:jid_to_string(From),
jlib:jid_to_string(To),
NewAttrs),
Text = xml:element_to_string({xmlelement, Name, Attrs2, Els}),
FixedPacket = {xmlelement, Name, Attrs2, Els},
Text = xml:element_to_string(FixedPacket),
send_text(StateData, Text),
ejabberd_hooks:run(user_receive_packet,
[StateData#state.jid, From, To, FixedPacket]),
{next_state, StateName, NewState};
true ->
{next_state, StateName, NewState}
@ -1102,6 +1110,8 @@ presence_update(From, Packet, StateData) ->
NewState =
if
FromUnavail ->
ejabberd_hooks:run(user_available_hook,
[StateData#state.jid]),
resend_offline_messages(StateData),
presence_broadcast_first(
From, StateData#state{pres_last = Packet,
@ -1385,17 +1395,37 @@ process_privacy_iq(From, To,
NewStateData.
resend_offline_messages(StateData) ->
resend_offline_messages(#state{user = User,
privacy_list = PrivList} = StateData) ->
case ejabberd_hooks:run_fold(resend_offline_messages_hook, [],
[StateData#state.user]) of
[User]) of
Rs when list(Rs) ->
lists:foreach(
fun({route, From, To, {xmlelement, Name, Attrs, Els}}) ->
Attrs2 = jlib:replace_from_to_attrs(
jlib:jid_to_string(From),
jlib:jid_to_string(To),
Attrs),
send_element(StateData, {xmlelement, Name, Attrs2, Els})
fun({route,
From, To, {xmlelement, Name, Attrs, Els} = Packet}) ->
Pass = case catch mod_privacy:check_packet(
User,
PrivList,
{From, To, Packet},
in) of
{'EXIT', _Reason} ->
true;
allow ->
true;
deny ->
false
end,
if
Pass ->
Attrs2 = jlib:replace_from_to_attrs(
jlib:jid_to_string(From),
jlib:jid_to_string(To),
Attrs),
send_element(StateData,
{xmlelement, Name, Attrs2, Els});
true ->
ok
end
end, Rs)
end.

View File

@ -55,7 +55,7 @@ run_fold(Hook, Val, Args) ->
[{_, Ls}] ->
run_fold1(Ls, Hook, Val, Args);
[] ->
ok
Val
end.
%%%----------------------------------------------------------------------

View File

@ -15,7 +15,8 @@
-export([register_iq_handler/3,
register_iq_handler/4,
unregister_iq_handler/1,
refresh_iq_handlers/0
refresh_iq_handlers/0,
bounce_resource_packet/3
]).
-include("ejabberd.hrl").
@ -32,6 +33,8 @@ init() ->
MyDomain = ?MYNAME,
ejabberd_router:register_route(MyDomain),
catch ets:new(local_iqtable, [named_table, public]),
ejabberd_hooks:add(local_send_to_resource_hook,
?MODULE, bounce_resource_packet, 100),
loop(#state{mydomain = MyDomain,
iqtable = local_iqtable}).
@ -104,14 +107,8 @@ do_route(State, From, To, Packet) ->
"error" -> ok;
"result" -> ok;
_ ->
case {Res, Name} of
{"announce/online", "message"} ->
announce_online(From, To, Packet);
_ ->
Err = jlib:make_error_reply(
Packet, ?ERR_ITEM_NOT_FOUND),
ejabberd_router:route(To, From, Err)
end
ejabberd_hooks:run(local_send_to_resource_hook,
[From, To, Packet])
end;
_ ->
ejabberd_sm ! {route, From, To, Packet}
@ -159,17 +156,7 @@ unregister_iq_handler(XMLNS) ->
refresh_iq_handlers() ->
ejabberd_local ! refresh_iq_handlers.
announce_online(From, To, Packet) ->
case acl:match_rule(announce, From) of
deny ->
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
ejabberd_router:route(To, From, Err);
allow ->
Local = jlib:make_jid("", ?MYNAME, ""),
lists:foreach(
fun({U, R}) ->
Dest = jlib:make_jid(U, ?MYNAME, R),
ejabberd_router:route(Local, Dest, Packet)
end, ejabberd_sm:dirty_get_sessions_list())
end.
bounce_resource_packet(From, To, Packet) ->
Err = jlib:make_error_reply(Packet, ?ERR_ITEM_NOT_FOUND),
ejabberd_router:route(To, From, Err),
stop.

178
src/mod_announce.erl Normal file
View File

@ -0,0 +1,178 @@
%%%----------------------------------------------------------------------
%%% File : mod_announce.erl
%%% Author : Alexey Shchepin <alexey@sevcom.net>
%%% Purpose : Manage announce messages
%%% Created : 11 Aug 2003 by Alexey Shchepin <alexey@sevcom.net>
%%% Id : $Id$
%%%----------------------------------------------------------------------
-module(mod_announce).
-author('alexey@sevcom.net').
-behaviour(gen_mod).
-export([start/1,
init/0,
stop/0,
announce/3,
send_motd/1]).
-include("ejabberd.hrl").
-include("jlib.hrl").
-record(motd, {id, packet}).
-record(motd_users, {luser, dummy = []}).
-define(PROCNAME, ejabberd_announce).
start(_) ->
mnesia:create_table(motd, [{disc_copies, [node()]},
{attributes, record_info(fields, motd)}]),
mnesia:create_table(motd_users, [{disc_copies, [node()]},
{attributes, record_info(fields, motd_users)}]),
ejabberd_hooks:add(local_send_to_resource_hook,
?MODULE, announce, 50),
ejabberd_hooks:add(user_available_hook,
?MODULE, send_motd, 50),
register(?PROCNAME, proc_lib:spawn(?MODULE, init, [])).
init() ->
loop().
loop() ->
receive
{announce_online, From, To, Packet} ->
announce_online(From, To, Packet),
loop();
{announce_motd, From, To, Packet} ->
announce_motd(From, To, Packet),
loop();
{announce_motd_update, From, To, Packet} ->
announce_motd_update(From, To, Packet),
loop();
{announce_motd_delete, From, To, Packet} ->
announce_motd_delete(From, To, Packet),
loop();
_ ->
loop()
end.
stop() ->
ejabberd_hooks:delete(local_send_to_resource_hook,
?MODULE, announce, 50),
ejabberd_hooks:delete(sm_register_connection_hook,
?MODULE, send_motd, 50),
exit(whereis(?PROCNAME), stop),
ok.
announce(From, To, Packet) ->
case To of
#jid{luser = "", lresource = Res} ->
{xmlelement, Name, _Attrs, _Els} = Packet,
case {Res, Name} of
{"announce/online", "message"} ->
?PROCNAME ! {announce_online, From, To, Packet},
stop;
{"announce/motd", "message"} ->
?PROCNAME ! {announce_motd, From, To, Packet},
stop;
{"announce/motd/update", "message"} ->
?PROCNAME ! {announce_motd_update, From, To, Packet},
stop;
{"announce/motd/delete", "message"} ->
?PROCNAME ! {announce_motd_delete, From, To, Packet},
stop;
_ ->
ok
end;
_ ->
ok
end.
announce_online(From, To, Packet) ->
Access = gen_mod:get_module_opt(?MODULE, access, none),
case acl:match_rule(Access, From) of
deny ->
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
ejabberd_router:route(To, From, Err);
allow ->
announce_online1(ejabberd_sm:dirty_get_sessions_list(), Packet)
end.
announce_online1(Sessions, Packet) ->
Server = ?MYNAME,
Local = jlib:make_jid("", Server, ""),
lists:foreach(
fun({U, R}) ->
Dest = jlib:make_jid(U, Server, R),
ejabberd_router:route(Local, Dest, Packet)
end, Sessions).
announce_motd(From, To, Packet) ->
Access = gen_mod:get_module_opt(?MODULE, access, none),
case acl:match_rule(Access, From) of
deny ->
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
ejabberd_router:route(To, From, Err);
allow ->
announce_motd_update(Packet),
Sessions = ejabberd_sm:dirty_get_sessions_list(),
announce_online1(Sessions, Packet),
F = fun() ->
lists:foreach(
fun({U, _R}) ->
mnesia:write(#motd_users{luser = U})
end, Sessions)
end,
mnesia:transaction(F)
end.
announce_motd_update(From, To, Packet) ->
Access = gen_mod:get_module_opt(?MODULE, access, none),
case acl:match_rule(Access, From) of
deny ->
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
ejabberd_router:route(To, From, Err);
allow ->
announce_motd_update(Packet)
end.
announce_motd_update(Packet) ->
announce_motd_delete(),
F = fun() ->
mnesia:write(#motd{id = motd, packet = Packet})
end,
mnesia:transaction(F).
announce_motd_delete(From, To, Packet) ->
Access = gen_mod:get_module_opt(?MODULE, access, none),
case acl:match_rule(Access, From) of
deny ->
Err = jlib:make_error_reply(Packet, ?ERR_NOT_ALLOWED),
ejabberd_router:route(To, From, Err);
allow ->
announce_motd_delete()
end.
announce_motd_delete() ->
mnesia:clear_table(motd),
mnesia:clear_table(motd_users).
send_motd(#jid{luser = LUser} = JID) ->
case catch mnesia:dirty_read({motd, motd}) of
[#motd{packet = Packet}] ->
case catch mnesia:dirty_read({motd_users, LUser}) of
[#motd_users{}] ->
ok;
_ ->
Local = jlib:make_jid("", ?MYNAME, ""),
ejabberd_router:route(Local, JID, Packet),
F = fun() ->
mnesia:write(#motd_users{luser = LUser})
end,
mnesia:transaction(F)
end;
_ ->
ok
end.