public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/ejabberd] f45: Ver. 2.0.5
@ 2026-09-23 19:06 Peter Lemenkov
  0 siblings, 0 replies; only message in thread
From: Peter Lemenkov @ 2026-09-23 19:06 UTC (permalink / raw)
  To: git-commits

A new commit has been pushed.

Repo   : rpms/ejabberd
Branch : f45
Commit : b83959148a9053fe57327981bbf1cfca742b2c8b
Author : Peter Lemenkov <peter@fedoraproject.org>
Date   : 2009-04-03T20:09:33+00:00
Stats  : +678/-17 in 6 file(s)
URL    : https://src.fedoraproject.org/rpms/ejabberd/c/b83959148a9053fe57327981bbf1cfca742b2c8b?branch=f45

Log:
Ver. 2.0.5

---
diff --git a/.cvsignore b/.cvsignore
index 7a2baca..7182d06 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -1 +1 @@
-ejabberd-2.0.4.tar.gz
+ejabberd-2.0.5.tar.gz

diff --git a/ejabberd-captcha.patch b/ejabberd-captcha.patch
new file mode 100644
index 0000000..4e9334b
--- /dev/null
+++ b/ejabberd-captcha.patch
@@ -0,0 +1,641 @@
+Binary files ejabberd-2.0.4/src/.DS_Store and ejabberd-2.0.4-new/src/.DS_Store differ
+diff -urN ejabberd-2.0.4/src/ejabberd_captcha.erl ejabberd-2.0.4-new/src/ejabberd_captcha.erl
+--- ejabberd-2.0.4/src/ejabberd_captcha.erl	1970-01-01 01:00:00.000000000 +0100
++++ ejabberd-2.0.4-new/src/ejabberd_captcha.erl	2009-03-14 07:27:05.000000000 +0100
+@@ -0,0 +1,312 @@
++%%%-------------------------------------------------------------------
++%%% File    : ejabberd_captcha.erl
++%%% Author  : Evgeniy Khramtsov <xramtsov@gmail.com>
++%%% Description : CAPTCHA processing.
++%%%
++%%% Created : 26 Apr 2008 by Evgeniy Khramtsov <xramtsov@gmail.com>
++%%%-------------------------------------------------------------------
++-module(ejabberd_captcha).
++
++-behaviour(gen_server).
++
++%% API
++-export([start_link/0]).
++
++%% gen_server callbacks
++-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
++	 terminate/2, code_change/3]).
++
++-export([create_captcha/6, process_reply/1, process/2]).
++
++-include("jlib.hrl").
++-include("ejabberd.hrl").
++-include("web/ejabberd_http.hrl").
++
++-define(VFIELD(Type, Var, Value),
++	{xmlelement, "field", [{"type", Type}, {"var", Var}],
++	 [{xmlelement, "value", [], [Value]}]}).
++
++-define(CAPTCHA_BODY(Lang, Room, URL),
++	translate:translate(Lang, "Your messages to ") ++ Room
++	++ translate:translate(Lang, " are being blocked. To unblock them, visit ")
++	++ URL).
++
++-define(CAPTCHA_TEXT(Lang), translate:translate(Lang, "Enter the text you see")).
++-define(CAPTCHA_LIFETIME, 120000). % two minutes
++
++-record(state, {}).
++-record(captcha, {id, pid, key, tref, args}).
++
++-define(T(S),
++	case catch mnesia:transaction(fun() -> S end) of
++	    {atomic, Res} ->
++		Res;
++	    {_, Reason} ->
++		?ERROR_MSG("mnesia transaction failed: ~p", [Reason]),
++		{error, Reason}
++	end).
++
++%%====================================================================
++%% API
++%%====================================================================
++%%--------------------------------------------------------------------
++%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
++%% Description: Starts the server
++%%--------------------------------------------------------------------
++start_link() ->
++    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
++
++create_captcha(Id, SID, From, To, Lang, Args)
++  when is_list(Id), is_list(Lang), is_list(SID),
++       is_record(From, jid), is_record(To, jid) ->
++    case create_image() of
++	{ok, Type, Key, Image} ->
++	    B64Image = jlib:encode_base64(binary_to_list(Image)),
++	    JID = jlib:jid_to_string(From),
++	    CID = "sha1+" ++ sha:sha(Image) ++ "@bob.xmpp.org",
++	    Data = {xmlelement, "data",
++		    [{"xmlns", ?NS_BOB}, {"cid", CID},
++		     {"max-age", "0"}, {"type", Type}],
++		    [{xmlcdata, B64Image}]},
++	    Captcha =
++		{xmlelement, "captcha", [{"xmlns", ?NS_CAPTCHA}],
++		 [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
++		   [?VFIELD("hidden", "FORM_TYPE", {xmlcdata, ?NS_CAPTCHA}),
++		    ?VFIELD("hidden", "from", {xmlcdata, jlib:jid_to_string(To)}),
++		    ?VFIELD("hidden", "challenge", {xmlcdata, Id}),
++		    ?VFIELD("hidden", "sid", {xmlcdata, SID}),
++		    {xmlelement, "field", [{"var", "ocr"}],
++		     [{xmlelement, "media", [{"xmlns", ?NS_MEDIA}],
++		       [{xmlelement, "uri", [{"type", Type}],
++			 [{xmlcdata, "cid:" ++ CID}]}]}]}]}]},
++	    Body = {xmlelement, "body", [],
++		    [{xmlcdata, ?CAPTCHA_BODY(Lang, JID, get_url(Id))}]},
++	    OOB = {xmlelement, "x", [{"xmlns", ?NS_OOB}],
++		   [{xmlelement, "url", [], [{xmlcdata, get_url(Id)}]}]},
++	    Tref = erlang:send_after(?CAPTCHA_LIFETIME, ?MODULE, {remove_id, Id}),
++	    ?T(mnesia:write(#captcha{id=Id, pid=self(), key=Key,
++				     tref=Tref, args=Args})),
++	    {ok, [Body, OOB, Captcha, Data]};
++	_Err ->
++	    error
++    end.
++
++process_reply({xmlelement, "captcha", _, _} = El) ->
++    case xml:get_subtag(El, "x") of
++	false ->
++	    {error, malformed};
++	Xdata ->
++	    Fields = jlib:parse_xdata_submit(Xdata),
++	    [Id | _] = proplists:get_value("challenge", Fields, [none]),
++	    [OCR | _] = proplists:get_value("ocr", Fields, [none]),
++	    ?T(case mnesia:read(captcha, Id, write) of
++		   [#captcha{pid=Pid, args=Args, key=Key, tref=Tref}] ->
++		       mnesia:delete({captcha, Id}),
++		       erlang:cancel_timer(Tref),
++		       if OCR == Key ->
++			       Pid ! {captcha_succeed, Args},
++			       ok;
++			  true ->
++			       Pid ! {captcha_failed, Args},
++			       {error, bad_match}
++		       end;
++		   _ ->
++		       {error, not_found}
++	       end)
++    end;
++process_reply(_) ->
++    {error, malformed}.
++
++process(_Handlers, #request{method='GET', lang=Lang, path=[_, Id]}) ->
++    case mnesia:dirty_read(captcha, Id) of
++	[#captcha{}] ->
++	    Form =
++		{xmlelement, "div", [{"align", "center"}],
++		 [{xmlelement, "form", [{"action", get_url(Id)},
++					{"name", "captcha"},
++					{"method", "POST"}],
++		   [{xmlelement, "img", [{"src", get_url(Id ++ "/image")}], []},
++		    {xmlelement, "br", [], []},
++		    {xmlcdata, ?CAPTCHA_TEXT(Lang)},
++		    {xmlelement, "br", [], []},
++		    {xmlelement, "input", [{"type", "text"},
++					   {"name", "key"},
++					   {"size", "10"}], []},
++		    {xmlelement, "br", [], []},
++		    {xmlelement, "input", [{"type", "submit"},
++					   {"name", "enter"},
++					   {"value", "OK"}], []}]}]},
++	    ejabberd_web:make_xhtml([Form]);
++	_ ->
++	    ejabberd_web:error(not_found)
++    end;
++
++process(_Handlers, #request{method='GET', path=[_, Id, "image"]}) ->
++    case mnesia:dirty_read(captcha, Id) of
++	[#captcha{key=Key}] ->
++	    case create_image(Key) of
++		{ok, Type, _, Img} ->
++		    {200,
++		     [{"Content-Type", Type},
++		      {"Cache-Control", "no-cache"},
++		      {"Last-Modified", httpd_util:rfc1123_date()}],
++		     Img};
++		_ ->
++		    ejabberd_web:error(not_found)
++	    end;
++	_ ->
++	    ejabberd_web:error(not_found)
++    end;
++
++process(_Handlers, #request{method='POST', q=Q, path=[_, Id]}) ->
++    ?T(case mnesia:read(captcha, Id, write) of
++	   [#captcha{pid=Pid, args=Args, key=Key, tref=Tref}] ->
++	       mnesia:delete({captcha, Id}),
++	       erlang:cancel_timer(Tref),
++	       Input = proplists:get_value("key", Q, none),
++	       if Input == Key ->
++		       Pid ! {captcha_succeed, Args},
++		       ejabberd_web:make_xhtml([]);
++		  true ->
++		       Pid ! {captcha_failed, Args},
++		       ejabberd_web:error(not_allowed)
++	       end;
++	   _ ->
++	       ejabberd_web:error(not_found)
++       end).
++
++%%====================================================================
++%% gen_server callbacks
++%%====================================================================
++init([]) ->
++    mnesia:create_table(captcha,
++			[{ram_copies, [node()]},
++			 {attributes, record_info(fields, captcha)}]),
++    mnesia:add_table_copy(captcha, node(), ram_copies),
++    {ok, #state{}}.
++
++handle_call(_Request, _From, State) ->
++    {reply, bad_request, State}.
++
++handle_cast(_Msg, State) ->
++    {noreply, State}.
++
++handle_info({remove_id, Id}, State) ->
++    ?DEBUG("captcha ~p timed out", [Id]),
++    ?T(case mnesia:read(captcha, Id, write) of
++	   [#captcha{args=Args, pid=Pid}] ->
++	       Pid ! {captcha_failed, Args},
++	       mnesia:delete({captcha, Id});
++	   _ ->
++	       ok
++       end),
++    {noreply, State};
++
++handle_info(_Info, State) ->
++    {noreply, State}.
++
++terminate(_Reason, _State) ->
++    ok.
++
++code_change(_OldVsn, State, _Extra) ->
++    {ok, State}.
++
++%%--------------------------------------------------------------------
++%%% Internal functions
++%%--------------------------------------------------------------------
++%%--------------------------------------------------------------------
++%% Function: create_image() -> {ok, Type, Key, Image} | {error, Reason}
++%% Type = "image/png" | "image/jpeg" | "image/gif"
++%% Key = string()
++%% Image = binary()
++%% Reason = atom()
++%%--------------------------------------------------------------------
++create_image() ->
++    %% Six numbers from 1 to 9.
++    Key = string:substr(randoms:get_string(), 1, 6),
++    create_image(Key).
++
++create_image(Key) ->
++    FileName = get_prog_name(),
++    Cmd = lists:flatten(io_lib:format("~s ~s", [FileName, Key])),
++    case cmd(Cmd) of
++	{ok, <<16#89, $P, $N, $G, $\r, $\n, 16#1a, $\n, _/binary>> = Img} ->
++	    {ok, "image/png", Key, Img};
++	{ok, <<16#ff, 16#d8, _/binary>> = Img} ->
++	    {ok, "image/jpeg", Key, Img};
++	{ok, <<$G, $I, $F, $8, X, $a, _/binary>> = Img} when X==$7; X==$9 ->
++	    {ok, "image/gif", Key, Img};
++	{error, Reason} ->
++	    ?ERROR_MSG("Failed to process an output from \"~s\": ~p",
++		       [Cmd, Reason]),
++	    {error, Reason};
++	_ ->
++	    Reason = malformed_image,
++	    ?ERROR_MSG("Failed to process an output from \"~s\": ~p",
++		       [Cmd, Reason]),
++	    {error, Reason}
++    end.
++
++get_prog_name() ->
++    case ejabberd_config:get_local_option(captcha_cmd) of
++	FileName when is_list(FileName) ->
++	    FileName;
++	_ ->
++	    ""
++    end.
++
++get_url(Str) ->
++    case ejabberd_config:get_local_option(captcha_host) of
++	Host when is_list(Host) ->
++	    "http://" ++ Host ++ "/captcha/" ++ Str;
++	_ ->
++	    "http://" ++ ?MYNAME ++ "/captcha/" ++ Str
++    end.
++
++%%--------------------------------------------------------------------
++%% Function: cmd(Cmd) -> Data | {error, Reason}
++%% Cmd = string()
++%% Data = binary()
++%% Description: os:cmd/1 replacement
++%%--------------------------------------------------------------------
++-define(CMD_TIMEOUT, 5000).
++-define(MAX_FILE_SIZE, 64*1024).
++
++cmd(Cmd) ->
++    Port = open_port({spawn, Cmd}, [stream, eof, binary]),
++    TRef = erlang:start_timer(?CMD_TIMEOUT, self(), timeout),
++    recv_data(Port, TRef, <<>>).
++
++recv_data(Port, TRef, Buf) ->
++    receive
++	{Port, {data, Bytes}} ->
++	    NewBuf = <<Buf/binary, Bytes/binary>>,
++	    if size(NewBuf) > ?MAX_FILE_SIZE ->
++		    return(Port, TRef, {error, efbig});
++	       true ->
++		    recv_data(Port, TRef, NewBuf)
++	    end;
++	{Port, {data, _}} ->
++	    return(Port, TRef, {error, efbig});
++	{Port, eof} when Buf /= <<>> ->
++	    return(Port, TRef, {ok, Buf});
++	{Port, eof} ->
++	    return(Port, TRef, {error, enodata});
++	{timeout, TRef, _} ->
++	    return(Port, TRef, {error, timeout})
++    end.
++
++return(Port, TRef, Result) ->
++    case erlang:cancel_timer(TRef) of
++	false ->
++	    receive
++		{timeout, TRef, _} ->
++		    ok
++	    after 0 ->
++		    ok
++	    end;
++	_ ->
++	    ok
++    end,
++    catch port_close(Port),
++    Result.
+diff -urN ejabberd-2.0.4/src/ejabberd_config.erl ejabberd-2.0.4-new/src/ejabberd_config.erl
+--- ejabberd-2.0.4/src/ejabberd_config.erl	2009-03-12 09:41:02.000000000 +0100
++++ ejabberd-2.0.4-new/src/ejabberd_config.erl	2009-03-14 11:43:35.000000000 +0100
+@@ -164,6 +164,10 @@
+ 	    add_option(watchdog_admins, Admins, State);
+ 	{registration_timeout, Timeout} ->
+ 	    add_option(registration_timeout, Timeout, State);
++	{captcha_cmd, Cmd} ->
++	    add_option(captcha_cmd, Cmd, State);
++	{captcha_host, Host} ->
++            add_option(captcha_host, Host, State);
+ 	{loglevel, Loglevel} ->
+ 	    ejabberd_loglevel:set(Loglevel),
+ 	    State;
+diff -urN ejabberd-2.0.4/src/ejabberd_sup.erl ejabberd-2.0.4-new/src/ejabberd_sup.erl
+--- ejabberd-2.0.4/src/ejabberd_sup.erl	2009-03-12 09:41:02.000000000 +0100
++++ ejabberd-2.0.4-new/src/ejabberd_sup.erl	2009-03-14 12:36:43.000000000 +0100
+@@ -84,6 +84,13 @@
+ 	 brutal_kill,
+ 	 worker,
+ 	 [ejabberd_local]},
++    Captcha =
++	{ejabberd_captcha,
++	 {ejabberd_captcha, start_link, []},
++	 permanent,
++	 brutal_kill,
++	 worker,
++	 [ejabberd_captcha]},
+     Listener =
+ 	{ejabberd_listener,
+ 	 {ejabberd_listener, start_link, []},
+@@ -170,6 +177,7 @@
+ 	   SM,
+ 	   S2S,
+ 	   Local,
++           Captcha,
+ 	   ReceiverSupervisor,
+ 	   C2SSupervisor,
+ 	   S2SInSupervisor,
+diff -urN ejabberd-2.0.4/src/jlib.hrl ejabberd-2.0.4-new/src/jlib.hrl
+--- ejabberd-2.0.4/src/jlib.hrl	2009-03-12 09:41:02.000000000 +0100
++++ ejabberd-2.0.4-new/src/jlib.hrl	2009-03-14 11:41:46.000000000 +0100
+@@ -74,6 +74,12 @@
+ 
+ -define(NS_CAPS,          "http://jabber.org/protocol/caps").
+ 
++%% CAPTCHA related NSes.
++-define(NS_OOB, "jabber:x:oob").
++-define(NS_CAPTCHA, "urn:xmpp:captcha").
++-define(NS_MEDIA, "urn:xmpp:media-element").
++-define(NS_BOB, "urn:xmpp:bob").
++
+ % TODO: remove "code" attribute (currently it used for backward-compatibility)
+ -define(STANZA_ERROR(Code, Type, Condition),
+ 	{xmlelement, "error",
+diff -urN ejabberd-2.0.4/src/mod_muc/mod_muc_room.erl ejabberd-2.0.4-new/src/mod_muc/mod_muc_room.erl
+--- ejabberd-2.0.4/src/mod_muc/mod_muc_room.erl	2009-03-12 09:41:02.000000000 +0100
++++ ejabberd-2.0.4-new/src/mod_muc/mod_muc_room.erl	2009-03-14 11:40:40.000000000 +0100
+@@ -69,6 +69,7 @@
+ 		 public_list = true,
+ 		 persistent = false,
+ 		 moderated = true,
++		 captcha_protected = false,
+ 		 members_by_default = true,
+ 		 members_only = false,
+ 		 allow_user_invites = false,
+@@ -98,6 +99,7 @@
+ 		jid,
+ 		config = #config{},
+ 		users = ?DICT:new(),
++		robots = ?DICT:new(),
+ 		affiliations = ?DICT:new(),
+ 		history = lqueue_new(20),
+ 		subject = "",
+@@ -382,7 +384,8 @@
+ 	      (XMLNS == ?NS_MUC_ADMIN) or
+ 	      (XMLNS == ?NS_MUC_OWNER) or
+ 	      (XMLNS == ?NS_DISCO_INFO) or
+-	      (XMLNS == ?NS_DISCO_ITEMS) ->
++	      (XMLNS == ?NS_DISCO_ITEMS) or 
++	      (XMLNS == ?NS_CAPTCHA) ->
+ 	    Res1 = case XMLNS of
+ 		       ?NS_MUC_ADMIN ->
+ 			   process_iq_admin(From, Type, Lang, SubEl, StateData);
+@@ -391,7 +394,9 @@
+ 		       ?NS_DISCO_INFO ->
+ 			   process_iq_disco_info(From, Type, Lang, StateData);
+ 		       ?NS_DISCO_ITEMS ->
+-			   process_iq_disco_items(From, Type, Lang, StateData)
++			   process_iq_disco_items(From, Type, Lang, StateData);
++		       ?NS_CAPTCHA ->
++			   process_iq_captcha(From, Type, Lang, SubEl, StateData)
+ 		   end,
+ 	    {IQRes, NewStateData} =
+ 		case Res1 of
+@@ -761,6 +766,30 @@
+ 	{empty, _} ->
+ 	    {next_state, StateName, StateData}
+     end;
++handle_info({captcha_succeed, From}, normal_state, StateData) ->
++    NewState = case ?DICT:find(From, StateData#state.robots) of
++		   {ok, {Nick, Packet}} ->
++		       Robots = ?DICT:store(From, passed, StateData#state.robots),
++		       add_new_user(From, Nick, Packet, StateData#state{robots=Robots});
++		   _ ->
++		       StateData
++	       end,
++    {next_state, normal_state, NewState};
++handle_info({captcha_failed, From}, normal_state, StateData) ->
++    NewState = case ?DICT:find(From, StateData#state.robots) of
++		   {ok, {Nick, Packet}} ->
++		       Robots = ?DICT:erase(From, StateData#state.robots),
++		       Err = jlib:make_error_reply(
++			       Packet, ?ERR_NOT_AUTHORIZED),
++		       ejabberd_router:route( % TODO: s/Nick/""/
++			 jlib:jid_replace_resource(
++			   StateData#state.jid, Nick),
++			 From, Err),
++		       StateData#state{robots=Robots};
++		   _ ->
++		       StateData
++	       end,
++    {next_state, normal_state, NewState};
+ handle_info(_Info, StateName, StateData) ->
+     {next_state, StateName, StateData}.
+ 
+@@ -1461,7 +1490,8 @@
+ 	      From, Err),
+ 	    StateData;
+ 	{_, _, _, Role} ->
+-	    case check_password(ServiceAffiliation, Els, StateData) of
++	    case check_password(ServiceAffiliation, Affiliation,
++				Els, From, StateData) of
+ 		true ->
+ 		    NewState =
+ 			add_user_presence(
+@@ -1494,7 +1524,8 @@
+ 			true ->
+ 			    NewState#state{just_created = false};
+ 			false ->
+-			    NewState
++			    Robots = ?DICT:erase(From, StateData#state.robots),
++			    NewState#state{robots = Robots}
+ 		    end;
+ 		nopass ->
+ 		    ErrText = "Password required to enter this room",
+@@ -1505,6 +1536,29 @@
+ 			StateData#state.jid, Nick),
+ 		      From, Err),
+ 		    StateData;
++                captcha_required ->
++		    ID = randoms:get_string(),
++		    SID = xml:get_attr_s("id", Attrs),
++		    RoomJID = StateData#state.jid,
++		    To = jlib:jid_replace_resource(RoomJID, Nick),
++		    case ejabberd_captcha:create_captcha(
++			   ID, SID, RoomJID, To, Lang, From) of
++			{ok, CaptchaEls} ->
++			    MsgPkt = {xmlelement, "message", [{"id", ID}], CaptchaEls},
++			    Robots = ?DICT:store(From,
++						 {Nick, Packet}, StateData#state.robots),
++			    ejabberd_router:route(RoomJID, From, MsgPkt),
++			    StateData#state{robots = Robots};
++			error ->
++			    ErrText = "Unable to generate a captcha",
++			    Err = jlib:make_error_reply(
++				    Packet, ?ERRT_INTERNAL_SERVER_ERROR(Lang, ErrText)),
++			    ejabberd_router:route( % TODO: s/Nick/""/
++			      jlib:jid_replace_resource(
++				StateData#state.jid, Nick),
++			      From, Err),
++			    StateData
++		    end;
+ 		_ ->
+ 		    ErrText = "Incorrect password",
+ 		    Err = jlib:make_error_reply(
+@@ -1517,13 +1571,13 @@
+ 	   end
+     end.
+ 
+-check_password(owner, _Els, _StateData) ->
++check_password(owner, _Affiliation, _Els, _From, _StateData) ->
+     %% Don't check pass if user is owner in MUC service (access_admin option)
+     true;
+-check_password(_ServiceAffiliation, Els, StateData) ->
++check_password(_ServiceAffiliation, Affiliation, Els, From, StateData) ->
+     case (StateData#state.config)#config.password_protected of
+ 	false ->
+-	    true;
++	    check_captcha(Affiliation, From, StateData);
+ 	true ->
+ 	    Pass = extract_password(Els),
+ 	    case Pass of
+@@ -1539,6 +1593,19 @@
+ 	    end
+     end.
+ 
++check_captcha(Affiliation, From, StateData) ->
++    case (StateData#state.config)#config.captcha_protected of
++	true when Affiliation == none ->
++	    case ?DICT:find(From, StateData#state.robots) of
++		{ok, passed} ->
++		    true;
++		_ ->
++		    captcha_required
++	    end;
++	_ ->
++	    true
++    end.
++
+ extract_password([]) ->
+     false;
+ extract_password([{xmlelement, _Name, Attrs, _SubEls} = El | Els]) ->
+@@ -2713,6 +2780,9 @@
+ 	 ?BOOLXFIELD("Make room members-only",
+ 		     "muc#roomconfig_membersonly",
+ 		     Config#config.members_only),
++	 ?BOOLXFIELD("Make room captcha protected",
++		     "captcha_protected",
++		     Config#config.captcha_protected),
+ 	 ?BOOLXFIELD("Make room moderated",
+ 		     "muc#roomconfig_moderatedroom",
+ 		     Config#config.moderated),
+@@ -2823,6 +2893,8 @@
+     ?SET_BOOL_XOPT(members_by_default, Val);
+ set_xoption([{"muc#roomconfig_membersonly", [Val]} | Opts], Config) ->
+     ?SET_BOOL_XOPT(members_only, Val);
++set_xoption([{"captcha_protected", [Val]} | Opts], Config) ->
++    ?SET_BOOL_XOPT(captcha_protected, Val);
+ set_xoption([{"muc#roomconfig_allowinvites", [Val]} | Opts], Config) ->
+     ?SET_BOOL_XOPT(allow_user_invites, Val);
+ set_xoption([{"muc#roomconfig_passwordprotectedroom", [Val]} | Opts], Config) ->
+@@ -2913,6 +2985,7 @@
+ 	      ?CASE_CONFIG_OPT(members_only);
+ 	      ?CASE_CONFIG_OPT(allow_user_invites);
+ 	      ?CASE_CONFIG_OPT(password_protected);
++	      ?CASE_CONFIG_OPT(captcha_protected);
+ 	      ?CASE_CONFIG_OPT(password);
+ 	      ?CASE_CONFIG_OPT(anonymous);
+ 	      ?CASE_CONFIG_OPT(logging);
+@@ -2954,6 +3027,7 @@
+      ?MAKE_CONFIG_OPT(members_only),
+      ?MAKE_CONFIG_OPT(allow_user_invites),
+      ?MAKE_CONFIG_OPT(password_protected),
++     ?MAKE_CONFIG_OPT(captcha_protected),
+      ?MAKE_CONFIG_OPT(password),
+      ?MAKE_CONFIG_OPT(anonymous),
+      ?MAKE_CONFIG_OPT(logging),
+@@ -3074,6 +3148,17 @@
+ 	    {error, ?ERR_FORBIDDEN}
+     end.
+ 
++process_iq_captcha(_From, get, _Lang, _SubEl, _StateData) ->
++    {error, ?ERR_NOT_ALLOWED};
++
++process_iq_captcha(_From, set, _Lang, SubEl, StateData) ->
++    case ejabberd_captcha:process_reply(SubEl) of
++	ok ->
++	    {result, [], StateData};
++	_ ->
++	    {error, ?ERR_NOT_ACCEPTABLE}
++    end.
++
+ get_title(StateData) ->
+     case (StateData#state.config)#config.title of
+ 	"" ->
+diff -urN ejabberd-2.0.4/src/web/ejabberd_http.erl ejabberd-2.0.4-new/src/web/ejabberd_http.erl
+--- ejabberd-2.0.4/src/web/ejabberd_http.erl	2009-03-12 09:41:02.000000000 +0100
++++ ejabberd-2.0.4-new/src/web/ejabberd_http.erl	2009-03-14 10:57:34.000000000 +0100
+@@ -106,6 +106,10 @@
+ 	    {value, {request_handlers, H}} -> H;
+ 	    false -> []
+         end ++
++	case lists:member(captcha, Opts) of
++	    true -> [{["captcha"], ejabberd_captcha}];
++	    false -> []
++	end ++
+         case lists:member(web_admin, Opts) of
+             true -> [{["admin"], ejabberd_web_admin}];
+             false -> []
+Binary files ejabberd-2.0.4/tools/.DS_Store and ejabberd-2.0.4-new/tools/.DS_Store differ
+diff -urN ejabberd-2.0.4/tools/captcha.sh ejabberd-2.0.4-new/tools/captcha.sh
+--- ejabberd-2.0.4/tools/captcha.sh	1970-01-01 01:00:00.000000000 +0100
++++ ejabberd-2.0.4-new/tools/captcha.sh	2009-03-14 11:46:42.000000000 +0100
+@@ -0,0 +1,21 @@
++#!/bin/sh
++
++SIGN=$(($RANDOM % 2))
++
++R1=$(($RANDOM % 20))
++R2=$(($RANDOM % 10 + 40))
++
++if [ $SIGN -eq "0" ]; then
++    S1=$(( -1*($RANDOM % 20 + 50) ))
++    S2=$(( $RANDOM % 20 + 50 ))
++else
++    S2=$(( -1*($RANDOM % 20 + 50) ))
++    S1=$(( $RANDOM % 20 + 50 ))
++fi
++
++convert -size 140x60 xc:white \
++    -pointsize 30 -draw "text 20,30 '$1'" \
++    -roll -$R2+$R1 -swirl $S1 \
++    -roll +$R2-$R1 -swirl $S2 \
++    +repage -resize 120x60 \
++    -quality 90 -depth 8 png:-
+--- ejabberd-2.0.5/ChangeLog~	2009-04-01 19:23:52.000000000 +0400
++++ ejabberd-2.0.5/ChangeLog	2009-04-03 23:45:03.174979944 +0400
+@@ -15,6 +15,15 @@
+ 	stanza (EJAB-300).
+ 	* src/ejabberd_c2s.erl: Likewise
+ 
++2009-03-13  Evgeniy Khramtsov <ekhramtsov@process-one.net>
++
++	* src/ejabberd_captcha.erl: XEP-158 (CAPTCHA Forms).
++	* src/ejabberd_config.erl: likewise.
++	* src/ejabberd_sup.erl: likewise.
++	* src/jlib.hrl: likewise.
++	* src/web/ejabberd_http.erl: likewise.
++	* src/mod_muc/mod_muc_room.erl: CAPTCHA support.
++
+ 2009-03-10  Badlop  <badlop@process-one.net>
+ 
+ 	* doc/release_notes_2.0.4.txt: Added file for new release

diff --git a/ejabberd.spec b/ejabberd.spec
index 386d8b6..a420d6e 100644
--- a/ejabberd.spec
+++ b/ejabberd.spec
@@ -1,5 +1,5 @@
 Name:           ejabberd
-Version:        2.0.4
+Version:        2.0.5
 Release:        1%{?dist}
 Summary:        A distributed, fault-tolerant Jabber/XMPP server
 
@@ -12,7 +12,7 @@ Source2:        ejabberd.logrotate
 Source3:	ejabberd.sysconfig
 
 # http://www.ejabberd.im/mod_ctlextra
-# svn export -r 557 https://svn.process-one.net/ejabberd-modules/mod_ctlextra/trunk/src/mod_ctlextra.erl
+# svn export -r 873 https://svn.process-one.net/ejabberd-modules/mod_ctlextra/trunk/src/mod_ctlextra.erl
 Source4:        mod_ctlextra.erl
 
 # The following were extracted from a patch found on http://realloc.spb.ru/share/ejabberdad.html
@@ -31,6 +31,10 @@ Patch1: ejabberd-build.patch
 Patch2: ejabberd-ejabberdctl_fix.diff
 # Use ejabberd as an example for PAM service name
 Patch3: ejabberd-ejabberd_cfg_pam_name.diff
+# CAPTCHA support, see https://support.process-one.net/doc/display/XAAI/Fighting+Multi-User+Chat+SPAM+with+CAPTCHA
+# wget https://support.process-one.net/secure/attachment/13851/XEP-0158_ejabberd-2.0.4.patch -O ejabberd-captcha.patch
+Patch4: ejabberd-captcha.patch
+
 
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
@@ -113,6 +117,7 @@ fi
 %patch1 -p0 -b .fix_paths
 %patch2 -p0 -b .fix_user
 %patch3 -p0 -b .pam_name
+#%patch4 -p1 -b .captcha
 dos2unix src/odbc/mssql.sql
 
 cp %{S:4} src
@@ -172,7 +177,7 @@ rm -rf %{buildroot}
 
 %files
 %defattr(-,root,root,-)
-%doc COPYING src/odbc/mysql.sql src/odbc/mssql.sql src/odbc/pg.sql
+%doc COPYING src/odbc/mysql.sql src/odbc/mssql.sql src/odbc/pg.sql tools/captcha.sh
 
 %attr(750,ejabberd,ejabberd) %dir %{_sysconfdir}/ejabberd
 %attr(640,ejabberd,ejabberd) %config(noreplace) %{_sysconfdir}/ejabberd/ejabberd.cfg
@@ -214,6 +219,14 @@ rm -rf %{buildroot}
 %endif
 
 %changelog
+* Fri Apr  3 2009 Peter Lemenkov <lemenkov@gmail.com> 2.0.5-1
+- Ver. 2.0.5
+- Temporarily disabled CAPTCHA support
+
+* Sun Mar 15 2009 Peter Lemenkov <lemenkov@gmail.com> 2.0.4-2
+- Support for CAPTCHA (XEP-0158)
+- Updated mod_ctlextra.erl (fixed EJAB-789, EJAB-864)
+
 * Sun Mar 15 2009 Peter Lemenkov <lemenkov@gmail.com> 2.0.4-1
 - Ver. 2.0.4
 

diff --git a/import.log b/import.log
index bad8533..0f0c5a2 100644
--- a/import.log
+++ b/import.log
@@ -6,3 +6,4 @@ ejabberd-2_0_2-1_fc9:HEAD:ejabberd-2.0.2-1.fc9.src.rpm:1220040866
 ejabberd-2_0_2-3_fc9:HEAD:ejabberd-2.0.2-3.fc9.src.rpm:1222925272
 ejabberd-2_0_3-1_fc10:HEAD:ejabberd-2.0.3-1.fc10.src.rpm:1232988133
 ejabberd-2_0_4-1_fc10:HEAD:ejabberd-2.0.4-1.fc10.src.rpm:1237116778
+ejabberd-2_0_5-1_fc10:HEAD:ejabberd-2.0.5-1.fc10.src.rpm:1238789339

diff --git a/mod_ctlextra.erl b/mod_ctlextra.erl
index 8753057..5c6c6c8 100644
--- a/mod_ctlextra.erl
+++ b/mod_ctlextra.erl
@@ -3,7 +3,7 @@
 %%% Author  : Badlop <badlop@ono.com>
 %%% Purpose : Adds more commands to ejabberd_ctl
 %%% Created : 30 Nov 2006 by Badlop <badlop@ono.com>
-%%% Id      : $Id: mod_ctlextra.erl 557 2008-04-25 22:01:13Z badlop $
+%%% Id      : $Id: mod_ctlextra.erl 873 2009-02-09 18:30:21Z badlop $
 %%%----------------------------------------------------------------------
 
 -module(mod_ctlextra).
@@ -47,14 +47,12 @@ commands_global() ->
 
      %% ejabberd_auth
      {"delete-older-users days", "delete users that have not logged in the last 'days'"},
+     {"delete-older-users-vhost host days", "delete users that not logged in last 'days' in 'host'"},
      {"set-password user server password", "set password to user@server"},
 
      %% ejd2odbc
      {"export2odbc server output", "export Mnesia tables on server to files on output directory"},
 
-     %% mod_offline
-     {"delete-older-messages days", "delete offline messages older than 'days'"},
-
      %% mod_shared_roster
      {"srg-create group host name description display", "create the group with options"},
      {"srg-delete group host", "delete the group"},
@@ -113,15 +111,16 @@ commands_host() ->
 %% Commands global
 %%-------------
 
-ctl_process(_Val, ["delete-older-messages", Days]) ->
-    mod_offline:remove_old_messages(list_to_integer(Days)),
-    ?STATUS_SUCCESS;
-
 ctl_process(_Val, ["delete-older-users", Days]) ->
     {removed, N, UR} = delete_older_users(list_to_integer(Days)),
     io:format("Deleted ~p users: ~p~n", [N, UR]),
     ?STATUS_SUCCESS;
 
+ctl_process(_Val, ["delete-older-users-vhost", Host, Days]) ->
+    {removed, N, UR} = delete_older_users_vhost(Host, list_to_integer(Days)),
+    io:format("Deleted ~p users: ~p~n", [N, UR]),
+    ?STATUS_SUCCESS;
+
 ctl_process(_Val, ["export2odbc", Server, Output]) ->
     Tables = [
 	      {export_last, last},
@@ -357,7 +356,7 @@ ctl_process(_Val, ["load-config", Path]) ->
 ctl_process(_Val, ["stats", Stat]) ->
     Res = case Stat of
 	      "uptime-seconds" -> uptime_seconds();
-	      "registeredusers" -> mnesia:table_info(passwd, size);
+	      "registeredusers" -> length(ejabberd_auth:dirty_get_registered_users());
 	      "onlineusersnode" -> length(ejabberd_sm:dirty_get_my_sessions_list());
 	      "onlineusers" -> length(ejabberd_sm:dirty_get_sessions_list())
 	  end,
@@ -752,6 +751,16 @@ update_vcard_els(Data, Content, Els1) ->
 -record(last_activity, {us, timestamp, status}).
 
 delete_older_users(Days) ->
+    %% Get the list of registered users
+    Users = ejabberd_auth:dirty_get_registered_users(),
+    delete_older_users(Days, Users).
+
+delete_older_users_vhost(Host, Days) ->
+    %% Get the list of registered users
+    Users = ejabberd_auth:get_vh_registered_users(Host),
+    delete_older_users(Days, Users).
+
+delete_older_users(Days, Users) ->
     %% Convert older time
     SecOlder = Days*24*60*60,
 
@@ -759,9 +768,6 @@ delete_older_users(Days) ->
     {MegaSecs, Secs, _MicroSecs} = now(),
     TimeStamp_now = MegaSecs * 1000000 + Secs,
 
-    %% Get the list of registered users
-    Users = ejabberd_auth:dirty_get_registered_users(),
-
     %% For a user, remove if required and answer true
     F = fun({LUser, LServer}) ->
 		%% Check if the user is logged

diff --git a/sources b/sources
index 26b2103..77e1427 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-1ff37c329e9bc1ddf3c458e051b81d63  ejabberd-2.0.4.tar.gz
+2d85b47df969daf0a78ed3b16562d731  ejabberd-2.0.5.tar.gz

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-23 19:06 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-23 19:06 [rpms/ejabberd] f45: Ver. 2.0.5 Peter Lemenkov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox