diff options
author | Alexey Shchepin <alexey@process-one.net> | 2004-08-12 22:34:19 +0000 |
---|---|---|
committer | Alexey Shchepin <alexey@process-one.net> | 2004-08-12 22:34:19 +0000 |
commit | d77a936b322220a67e703525ff585660ea8da670 (patch) | |
tree | 69c3cb1dfd199de6f78884f1e3db9a991958c42e | |
parent | * src/ejabberd_c2s.erl: Use resend_offline_messages_hook to fetch (diff) |
* 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
-rw-r--r-- | ChangeLog | 19 | ||||
-rw-r--r-- | doc/guide.html | 107 | ||||
-rw-r--r-- | doc/guide.tex | 26 | ||||
-rw-r--r-- | src/cyrsasl_digest.erl | 4 | ||||
-rw-r--r-- | src/ejabberd.cfg.example | 1 | ||||
-rw-r--r-- | src/ejabberd_c2s.erl | 48 | ||||
-rw-r--r-- | src/ejabberd_hooks.erl | 2 | ||||
-rw-r--r-- | src/ejabberd_local.erl | 33 | ||||
-rw-r--r-- | src/mod_announce.erl | 178 |
9 files changed, 342 insertions, 76 deletions
@@ -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 diff --git a/doc/guide.html b/doc/guide.html index 851bb0384..1d0927ac8 100644 --- a/doc/guide.html +++ b/doc/guide.html @@ -85,24 +85,25 @@ <A HREF="#htoc30">A.1.1 Option <TT>iqdisc</TT></A> <LI><A HREF="#htoc31">A.1.2 Option <TT>host</TT></A> </UL> -<LI><A HREF="#htoc32">A.2 <TT>mod_configure</TT></A> -<LI><A HREF="#htoc33">A.3 <TT>mod_disco</TT></A> -<LI><A HREF="#htoc34">A.4 <TT>mod_echo</TT></A> -<LI><A HREF="#htoc35">A.5 <TT>mod_irc</TT></A> -<LI><A HREF="#htoc36">A.6 <TT>mod_last</TT></A> -<LI><A HREF="#htoc37">A.7 <TT>mod_muc</TT></A> -<LI><A HREF="#htoc38">A.8 <TT>mod_offline</TT></A> -<LI><A HREF="#htoc39">A.9 <TT>mod_privacy</TT></A> -<LI><A HREF="#htoc40">A.10 <TT>mod_private</TT></A> -<LI><A HREF="#htoc41">A.11 <TT>mod_pubsub</TT></A> -<LI><A HREF="#htoc42">A.12 <TT>mod_register</TT></A> -<LI><A HREF="#htoc43">A.13 <TT>mod_roster</TT></A> -<LI><A HREF="#htoc44">A.14 <TT>mod_stats</TT></A> -<LI><A HREF="#htoc45">A.15 <TT>mod_time</TT></A> -<LI><A HREF="#htoc46">A.16 <TT>mod_vcard</TT></A> -<LI><A HREF="#htoc47">A.17 <TT>mod_version</TT></A> +<LI><A HREF="#htoc32">A.2 <TT>mod_announce</TT></A> +<LI><A HREF="#htoc33">A.3 <TT>mod_configure</TT></A> +<LI><A HREF="#htoc34">A.4 <TT>mod_disco</TT></A> +<LI><A HREF="#htoc35">A.5 <TT>mod_echo</TT></A> +<LI><A HREF="#htoc36">A.6 <TT>mod_irc</TT></A> +<LI><A HREF="#htoc37">A.7 <TT>mod_last</TT></A> +<LI><A HREF="#htoc38">A.8 <TT>mod_muc</TT></A> +<LI><A HREF="#htoc39">A.9 <TT>mod_offline</TT></A> +<LI><A HREF="#htoc40">A.10 <TT>mod_privacy</TT></A> +<LI><A HREF="#htoc41">A.11 <TT>mod_private</TT></A> +<LI><A HREF="#htoc42">A.12 <TT>mod_pubsub</TT></A> +<LI><A HREF="#htoc43">A.13 <TT>mod_register</TT></A> +<LI><A HREF="#htoc44">A.14 <TT>mod_roster</TT></A> +<LI><A HREF="#htoc45">A.15 <TT>mod_stats</TT></A> +<LI><A HREF="#htoc46">A.16 <TT>mod_time</TT></A> +<LI><A HREF="#htoc47">A.17 <TT>mod_vcard</TT></A> +<LI><A HREF="#htoc48">A.18 <TT>mod_version</TT></A> </UL> -<LI><A HREF="#htoc48">B I18n/L10n</A> +<LI><A HREF="#htoc49">B 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> <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> <TT>mod_configure</TT></H3><!--SEC END --> +<H3><A NAME="htoc33">A.3</A> <TT>mod_configure</TT></H3><!--SEC END --> <A NAME="sec:modconfigure"></A> Options: @@ -830,7 +855,7 @@ discipline (see <A HREF="#sec:modiqdiscoption">A.1.1</A>). </DL> <!--TOC subsection <TT>mod_disco</TT>--> -<H3><A NAME="htoc33">A.3</A> <TT>mod_disco</TT></H3><!--SEC END --> +<H3><A NAME="htoc34">A.4</A> <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> <TT>mod_echo</TT></H3><!--SEC END --> +<H3><A NAME="htoc35">A.5</A> <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> <TT>mod_irc</TT></H3><!--SEC END --> +<H3><A NAME="htoc36">A.6</A> <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> <TT>mod_last</TT></H3><!--SEC END --> +<H3><A NAME="htoc37">A.7</A> <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 <A HREF="#sec:modiqdiscoption">A.1.1</A>). </DL> <!--TOC subsection <TT>mod_muc</TT>--> -<H3><A NAME="htoc37">A.7</A> <TT>mod_muc</TT></H3><!--SEC END --> +<H3><A NAME="htoc38">A.8</A> <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> <TT>mod_offline</TT></H3><!--SEC END --> +<H3><A NAME="htoc39">A.9</A> <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> <TT>mod_privacy</TT></H3><!--SEC END --> +<H3><A NAME="htoc40">A.10</A> <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 <A HREF="#sec:modiqdiscoption">A.1.1</A>). </DL> <!--TOC subsection <TT>mod_private</TT>--> -<H3><A NAME="htoc40">A.10</A> <TT>mod_private</TT></H3><!--SEC END --> +<H3><A NAME="htoc41">A.11</A> <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 <A HREF="#sec:modiqdiscoption">A.1.1</A>). </DL> <!--TOC subsection <TT>mod_pubsub</TT>--> -<H3><A NAME="htoc41">A.11</A> <TT>mod_pubsub</TT></H3><!--SEC END --> +<H3><A NAME="htoc42">A.12</A> <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> <TT>mod_register</TT></H3><!--SEC END --> +<H3><A NAME="htoc43">A.13</A> <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> <TT>mod_roster</TT></H3><!--SEC END --> +<H3><A NAME="htoc44">A.14</A> <TT>mod_roster</TT></H3><!--SEC END --> <A NAME="sec:modroster"></A> This module implements roster management.<BR> @@ -1041,7 +1066,7 @@ discipline (see <A HREF="#sec:modiqdiscoption">A.1.1</A>). </DL> <!--TOC subsection <TT>mod_stats</TT>--> -<H3><A NAME="htoc44">A.14</A> <TT>mod_stats</TT></H3><!--SEC END --> +<H3><A NAME="htoc45">A.15</A> <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> <TT>mod_time</TT></H3><!--SEC END --> +<H3><A NAME="htoc46">A.16</A> <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 <A HREF="#sec:modiqdiscoption">A.1.1</A>). </DL> <!--TOC subsection <TT>mod_vcard</TT>--> -<H3><A NAME="htoc46">A.16</A> <TT>mod_vcard</TT></H3><!--SEC END --> +<H3><A NAME="htoc47">A.17</A> <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> <TT>mod_version</TT></H3><!--SEC END --> +<H3><A NAME="htoc48">A.18</A> <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 <A HREF="#sec:modiqdiscoption">A.1.1</A>). </DL> <!--TOC section I18n/L10n--> -<H2><A NAME="htoc48">B</A> I18n/L10n</H2><!--SEC END --> +<H2><A NAME="htoc49">B</A> I18n/L10n</H2><!--SEC END --> <A NAME="sec:i18nl10n"></A> All built-in modules support <TT>xml:lang</TT> attribute inside IQ queries. diff --git a/doc/guide.tex b/doc/guide.tex index dd78dbb98..5e12c70db 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -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} diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl index ae94c181f..2e5e94e5a 100644 --- a/src/cyrsasl_digest.erl +++ b/src/cyrsasl_digest.erl @@ -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; diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example index 82e1cc43c..253752f53 100644 --- a/src/ejabberd.cfg.example +++ b/src/ejabberd.cfg.example @@ -121,6 +121,7 @@ {mod_stats, []}, {mod_vcard, []}, {mod_offline, []}, + {mod_announce, [{access, announce}]}, {mod_echo, [{host, "echo.localhost"}]}, {mod_private, []}, {mod_irc, []}, diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 844e7bcfb..d8021606f 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -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. diff --git a/src/ejabberd_hooks.erl b/src/ejabberd_hooks.erl index c00035b41..d316fae89 100644 --- a/src/ejabberd_hooks.erl +++ b/src/ejabberd_hooks.erl @@ -55,7 +55,7 @@ run_fold(Hook, Val, Args) -> [{_, Ls}] -> run_fold1(Ls, Hook, Val, Args); [] -> - ok + Val end. %%%---------------------------------------------------------------------- diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl index 446ec292b..5da4cfaa1 100644 --- a/src/ejabberd_local.erl +++ b/src/ejabberd_local.erl @@ -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. diff --git a/src/mod_announce.erl b/src/mod_announce.erl new file mode 100644 index 000000000..29ac65e87 --- /dev/null +++ b/src/mod_announce.erl @@ -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. + |