/[smecontribs]/rpms/ejabberd/contribs7/ejabberd-captcha.patch
ViewVC logotype

Contents of /rpms/ejabberd/contribs7/ejabberd-captcha.patch

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download)
Mon Aug 24 18:19:21 2009 UTC (15 years, 2 months ago) by slords
Branch: MAIN
CVS Tags: ejabberd-2_0_5-2_el4_sme, HEAD
Error occurred while calculating annotation data.
New package import

1 Binary files ejabberd-2.0.4/src/.DS_Store and ejabberd-2.0.4-new/src/.DS_Store differ
2 diff -urN ejabberd-2.0.4/src/ejabberd_captcha.erl ejabberd-2.0.4-new/src/ejabberd_captcha.erl
3 --- ejabberd-2.0.4/src/ejabberd_captcha.erl 1970-01-01 01:00:00.000000000 +0100
4 +++ ejabberd-2.0.4-new/src/ejabberd_captcha.erl 2009-03-14 07:27:05.000000000 +0100
5 @@ -0,0 +1,312 @@
6 +%%%-------------------------------------------------------------------
7 +%%% File : ejabberd_captcha.erl
8 +%%% Author : Evgeniy Khramtsov <xramtsov@gmail.com>
9 +%%% Description : CAPTCHA processing.
10 +%%%
11 +%%% Created : 26 Apr 2008 by Evgeniy Khramtsov <xramtsov@gmail.com>
12 +%%%-------------------------------------------------------------------
13 +-module(ejabberd_captcha).
14 +
15 +-behaviour(gen_server).
16 +
17 +%% API
18 +-export([start_link/0]).
19 +
20 +%% gen_server callbacks
21 +-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
22 + terminate/2, code_change/3]).
23 +
24 +-export([create_captcha/6, process_reply/1, process/2]).
25 +
26 +-include("jlib.hrl").
27 +-include("ejabberd.hrl").
28 +-include("web/ejabberd_http.hrl").
29 +
30 +-define(VFIELD(Type, Var, Value),
31 + {xmlelement, "field", [{"type", Type}, {"var", Var}],
32 + [{xmlelement, "value", [], [Value]}]}).
33 +
34 +-define(CAPTCHA_BODY(Lang, Room, URL),
35 + translate:translate(Lang, "Your messages to ") ++ Room
36 + ++ translate:translate(Lang, " are being blocked. To unblock them, visit ")
37 + ++ URL).
38 +
39 +-define(CAPTCHA_TEXT(Lang), translate:translate(Lang, "Enter the text you see")).
40 +-define(CAPTCHA_LIFETIME, 120000). % two minutes
41 +
42 +-record(state, {}).
43 +-record(captcha, {id, pid, key, tref, args}).
44 +
45 +-define(T(S),
46 + case catch mnesia:transaction(fun() -> S end) of
47 + {atomic, Res} ->
48 + Res;
49 + {_, Reason} ->
50 + ?ERROR_MSG("mnesia transaction failed: ~p", [Reason]),
51 + {error, Reason}
52 + end).
53 +
54 +%%====================================================================
55 +%% API
56 +%%====================================================================
57 +%%--------------------------------------------------------------------
58 +%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
59 +%% Description: Starts the server
60 +%%--------------------------------------------------------------------
61 +start_link() ->
62 + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
63 +
64 +create_captcha(Id, SID, From, To, Lang, Args)
65 + when is_list(Id), is_list(Lang), is_list(SID),
66 + is_record(From, jid), is_record(To, jid) ->
67 + case create_image() of
68 + {ok, Type, Key, Image} ->
69 + B64Image = jlib:encode_base64(binary_to_list(Image)),
70 + JID = jlib:jid_to_string(From),
71 + CID = "sha1+" ++ sha:sha(Image) ++ "@bob.xmpp.org",
72 + Data = {xmlelement, "data",
73 + [{"xmlns", ?NS_BOB}, {"cid", CID},
74 + {"max-age", "0"}, {"type", Type}],
75 + [{xmlcdata, B64Image}]},
76 + Captcha =
77 + {xmlelement, "captcha", [{"xmlns", ?NS_CAPTCHA}],
78 + [{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
79 + [?VFIELD("hidden", "FORM_TYPE", {xmlcdata, ?NS_CAPTCHA}),
80 + ?VFIELD("hidden", "from", {xmlcdata, jlib:jid_to_string(To)}),
81 + ?VFIELD("hidden", "challenge", {xmlcdata, Id}),
82 + ?VFIELD("hidden", "sid", {xmlcdata, SID}),
83 + {xmlelement, "field", [{"var", "ocr"}],
84 + [{xmlelement, "media", [{"xmlns", ?NS_MEDIA}],
85 + [{xmlelement, "uri", [{"type", Type}],
86 + [{xmlcdata, "cid:" ++ CID}]}]}]}]}]},
87 + Body = {xmlelement, "body", [],
88 + [{xmlcdata, ?CAPTCHA_BODY(Lang, JID, get_url(Id))}]},
89 + OOB = {xmlelement, "x", [{"xmlns", ?NS_OOB}],
90 + [{xmlelement, "url", [], [{xmlcdata, get_url(Id)}]}]},
91 + Tref = erlang:send_after(?CAPTCHA_LIFETIME, ?MODULE, {remove_id, Id}),
92 + ?T(mnesia:write(#captcha{id=Id, pid=self(), key=Key,
93 + tref=Tref, args=Args})),
94 + {ok, [Body, OOB, Captcha, Data]};
95 + _Err ->
96 + error
97 + end.
98 +
99 +process_reply({xmlelement, "captcha", _, _} = El) ->
100 + case xml:get_subtag(El, "x") of
101 + false ->
102 + {error, malformed};
103 + Xdata ->
104 + Fields = jlib:parse_xdata_submit(Xdata),
105 + [Id | _] = proplists:get_value("challenge", Fields, [none]),
106 + [OCR | _] = proplists:get_value("ocr", Fields, [none]),
107 + ?T(case mnesia:read(captcha, Id, write) of
108 + [#captcha{pid=Pid, args=Args, key=Key, tref=Tref}] ->
109 + mnesia:delete({captcha, Id}),
110 + erlang:cancel_timer(Tref),
111 + if OCR == Key ->
112 + Pid ! {captcha_succeed, Args},
113 + ok;
114 + true ->
115 + Pid ! {captcha_failed, Args},
116 + {error, bad_match}
117 + end;
118 + _ ->
119 + {error, not_found}
120 + end)
121 + end;
122 +process_reply(_) ->
123 + {error, malformed}.
124 +
125 +process(_Handlers, #request{method='GET', lang=Lang, path=[_, Id]}) ->
126 + case mnesia:dirty_read(captcha, Id) of
127 + [#captcha{}] ->
128 + Form =
129 + {xmlelement, "div", [{"align", "center"}],
130 + [{xmlelement, "form", [{"action", get_url(Id)},
131 + {"name", "captcha"},
132 + {"method", "POST"}],
133 + [{xmlelement, "img", [{"src", get_url(Id ++ "/image")}], []},
134 + {xmlelement, "br", [], []},
135 + {xmlcdata, ?CAPTCHA_TEXT(Lang)},
136 + {xmlelement, "br", [], []},
137 + {xmlelement, "input", [{"type", "text"},
138 + {"name", "key"},
139 + {"size", "10"}], []},
140 + {xmlelement, "br", [], []},
141 + {xmlelement, "input", [{"type", "submit"},
142 + {"name", "enter"},
143 + {"value", "OK"}], []}]}]},
144 + ejabberd_web:make_xhtml([Form]);
145 + _ ->
146 + ejabberd_web:error(not_found)
147 + end;
148 +
149 +process(_Handlers, #request{method='GET', path=[_, Id, "image"]}) ->
150 + case mnesia:dirty_read(captcha, Id) of
151 + [#captcha{key=Key}] ->
152 + case create_image(Key) of
153 + {ok, Type, _, Img} ->
154 + {200,
155 + [{"Content-Type", Type},
156 + {"Cache-Control", "no-cache"},
157 + {"Last-Modified", httpd_util:rfc1123_date()}],
158 + Img};
159 + _ ->
160 + ejabberd_web:error(not_found)
161 + end;
162 + _ ->
163 + ejabberd_web:error(not_found)
164 + end;
165 +
166 +process(_Handlers, #request{method='POST', q=Q, path=[_, Id]}) ->
167 + ?T(case mnesia:read(captcha, Id, write) of
168 + [#captcha{pid=Pid, args=Args, key=Key, tref=Tref}] ->
169 + mnesia:delete({captcha, Id}),
170 + erlang:cancel_timer(Tref),
171 + Input = proplists:get_value("key", Q, none),
172 + if Input == Key ->
173 + Pid ! {captcha_succeed, Args},
174 + ejabberd_web:make_xhtml([]);
175 + true ->
176 + Pid ! {captcha_failed, Args},
177 + ejabberd_web:error(not_allowed)
178 + end;
179 + _ ->
180 + ejabberd_web:error(not_found)
181 + end).
182 +
183 +%%====================================================================
184 +%% gen_server callbacks
185 +%%====================================================================
186 +init([]) ->
187 + mnesia:create_table(captcha,
188 + [{ram_copies, [node()]},
189 + {attributes, record_info(fields, captcha)}]),
190 + mnesia:add_table_copy(captcha, node(), ram_copies),
191 + {ok, #state{}}.
192 +
193 +handle_call(_Request, _From, State) ->
194 + {reply, bad_request, State}.
195 +
196 +handle_cast(_Msg, State) ->
197 + {noreply, State}.
198 +
199 +handle_info({remove_id, Id}, State) ->
200 + ?DEBUG("captcha ~p timed out", [Id]),
201 + ?T(case mnesia:read(captcha, Id, write) of
202 + [#captcha{args=Args, pid=Pid}] ->
203 + Pid ! {captcha_failed, Args},
204 + mnesia:delete({captcha, Id});
205 + _ ->
206 + ok
207 + end),
208 + {noreply, State};
209 +
210 +handle_info(_Info, State) ->
211 + {noreply, State}.
212 +
213 +terminate(_Reason, _State) ->
214 + ok.
215 +
216 +code_change(_OldVsn, State, _Extra) ->
217 + {ok, State}.
218 +
219 +%%--------------------------------------------------------------------
220 +%%% Internal functions
221 +%%--------------------------------------------------------------------
222 +%%--------------------------------------------------------------------
223 +%% Function: create_image() -> {ok, Type, Key, Image} | {error, Reason}
224 +%% Type = "image/png" | "image/jpeg" | "image/gif"
225 +%% Key = string()
226 +%% Image = binary()
227 +%% Reason = atom()
228 +%%--------------------------------------------------------------------
229 +create_image() ->
230 + %% Six numbers from 1 to 9.
231 + Key = string:substr(randoms:get_string(), 1, 6),
232 + create_image(Key).
233 +
234 +create_image(Key) ->
235 + FileName = get_prog_name(),
236 + Cmd = lists:flatten(io_lib:format("~s ~s", [FileName, Key])),
237 + case cmd(Cmd) of
238 + {ok, <<16#89, $P, $N, $G, $\r, $\n, 16#1a, $\n, _/binary>> = Img} ->
239 + {ok, "image/png", Key, Img};
240 + {ok, <<16#ff, 16#d8, _/binary>> = Img} ->
241 + {ok, "image/jpeg", Key, Img};
242 + {ok, <<$G, $I, $F, $8, X, $a, _/binary>> = Img} when X==$7; X==$9 ->
243 + {ok, "image/gif", Key, Img};
244 + {error, Reason} ->
245 + ?ERROR_MSG("Failed to process an output from \"~s\": ~p",
246 + [Cmd, Reason]),
247 + {error, Reason};
248 + _ ->
249 + Reason = malformed_image,
250 + ?ERROR_MSG("Failed to process an output from \"~s\": ~p",
251 + [Cmd, Reason]),
252 + {error, Reason}
253 + end.
254 +
255 +get_prog_name() ->
256 + case ejabberd_config:get_local_option(captcha_cmd) of
257 + FileName when is_list(FileName) ->
258 + FileName;
259 + _ ->
260 + ""
261 + end.
262 +
263 +get_url(Str) ->
264 + case ejabberd_config:get_local_option(captcha_host) of
265 + Host when is_list(Host) ->
266 + "http://" ++ Host ++ "/captcha/" ++ Str;
267 + _ ->
268 + "http://" ++ ?MYNAME ++ "/captcha/" ++ Str
269 + end.
270 +
271 +%%--------------------------------------------------------------------
272 +%% Function: cmd(Cmd) -> Data | {error, Reason}
273 +%% Cmd = string()
274 +%% Data = binary()
275 +%% Description: os:cmd/1 replacement
276 +%%--------------------------------------------------------------------
277 +-define(CMD_TIMEOUT, 5000).
278 +-define(MAX_FILE_SIZE, 64*1024).
279 +
280 +cmd(Cmd) ->
281 + Port = open_port({spawn, Cmd}, [stream, eof, binary]),
282 + TRef = erlang:start_timer(?CMD_TIMEOUT, self(), timeout),
283 + recv_data(Port, TRef, <<>>).
284 +
285 +recv_data(Port, TRef, Buf) ->
286 + receive
287 + {Port, {data, Bytes}} ->
288 + NewBuf = <<Buf/binary, Bytes/binary>>,
289 + if size(NewBuf) > ?MAX_FILE_SIZE ->
290 + return(Port, TRef, {error, efbig});
291 + true ->
292 + recv_data(Port, TRef, NewBuf)
293 + end;
294 + {Port, {data, _}} ->
295 + return(Port, TRef, {error, efbig});
296 + {Port, eof} when Buf /= <<>> ->
297 + return(Port, TRef, {ok, Buf});
298 + {Port, eof} ->
299 + return(Port, TRef, {error, enodata});
300 + {timeout, TRef, _} ->
301 + return(Port, TRef, {error, timeout})
302 + end.
303 +
304 +return(Port, TRef, Result) ->
305 + case erlang:cancel_timer(TRef) of
306 + false ->
307 + receive
308 + {timeout, TRef, _} ->
309 + ok
310 + after 0 ->
311 + ok
312 + end;
313 + _ ->
314 + ok
315 + end,
316 + catch port_close(Port),
317 + Result.
318 diff -urN ejabberd-2.0.4/src/ejabberd_config.erl ejabberd-2.0.4-new/src/ejabberd_config.erl
319 --- ejabberd-2.0.4/src/ejabberd_config.erl 2009-03-12 09:41:02.000000000 +0100
320 +++ ejabberd-2.0.4-new/src/ejabberd_config.erl 2009-03-14 11:43:35.000000000 +0100
321 @@ -164,6 +164,10 @@
322 add_option(watchdog_admins, Admins, State);
323 {registration_timeout, Timeout} ->
324 add_option(registration_timeout, Timeout, State);
325 + {captcha_cmd, Cmd} ->
326 + add_option(captcha_cmd, Cmd, State);
327 + {captcha_host, Host} ->
328 + add_option(captcha_host, Host, State);
329 {loglevel, Loglevel} ->
330 ejabberd_loglevel:set(Loglevel),
331 State;
332 diff -urN ejabberd-2.0.4/src/ejabberd_sup.erl ejabberd-2.0.4-new/src/ejabberd_sup.erl
333 --- ejabberd-2.0.4/src/ejabberd_sup.erl 2009-03-12 09:41:02.000000000 +0100
334 +++ ejabberd-2.0.4-new/src/ejabberd_sup.erl 2009-03-14 12:36:43.000000000 +0100
335 @@ -84,6 +84,13 @@
336 brutal_kill,
337 worker,
338 [ejabberd_local]},
339 + Captcha =
340 + {ejabberd_captcha,
341 + {ejabberd_captcha, start_link, []},
342 + permanent,
343 + brutal_kill,
344 + worker,
345 + [ejabberd_captcha]},
346 Listener =
347 {ejabberd_listener,
348 {ejabberd_listener, start_link, []},
349 @@ -170,6 +177,7 @@
350 SM,
351 S2S,
352 Local,
353 + Captcha,
354 ReceiverSupervisor,
355 C2SSupervisor,
356 S2SInSupervisor,
357 diff -urN ejabberd-2.0.4/src/jlib.hrl ejabberd-2.0.4-new/src/jlib.hrl
358 --- ejabberd-2.0.4/src/jlib.hrl 2009-03-12 09:41:02.000000000 +0100
359 +++ ejabberd-2.0.4-new/src/jlib.hrl 2009-03-14 11:41:46.000000000 +0100
360 @@ -74,6 +74,12 @@
361
362 -define(NS_CAPS, "http://jabber.org/protocol/caps").
363
364 +%% CAPTCHA related NSes.
365 +-define(NS_OOB, "jabber:x:oob").
366 +-define(NS_CAPTCHA, "urn:xmpp:captcha").
367 +-define(NS_MEDIA, "urn:xmpp:media-element").
368 +-define(NS_BOB, "urn:xmpp:bob").
369 +
370 % TODO: remove "code" attribute (currently it used for backward-compatibility)
371 -define(STANZA_ERROR(Code, Type, Condition),
372 {xmlelement, "error",
373 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
374 --- ejabberd-2.0.4/src/mod_muc/mod_muc_room.erl 2009-03-12 09:41:02.000000000 +0100
375 +++ ejabberd-2.0.4-new/src/mod_muc/mod_muc_room.erl 2009-03-14 11:40:40.000000000 +0100
376 @@ -69,6 +69,7 @@
377 public_list = true,
378 persistent = false,
379 moderated = true,
380 + captcha_protected = false,
381 members_by_default = true,
382 members_only = false,
383 allow_user_invites = false,
384 @@ -98,6 +99,7 @@
385 jid,
386 config = #config{},
387 users = ?DICT:new(),
388 + robots = ?DICT:new(),
389 affiliations = ?DICT:new(),
390 history = lqueue_new(20),
391 subject = "",
392 @@ -382,7 +384,8 @@
393 (XMLNS == ?NS_MUC_ADMIN) or
394 (XMLNS == ?NS_MUC_OWNER) or
395 (XMLNS == ?NS_DISCO_INFO) or
396 - (XMLNS == ?NS_DISCO_ITEMS) ->
397 + (XMLNS == ?NS_DISCO_ITEMS) or
398 + (XMLNS == ?NS_CAPTCHA) ->
399 Res1 = case XMLNS of
400 ?NS_MUC_ADMIN ->
401 process_iq_admin(From, Type, Lang, SubEl, StateData);
402 @@ -391,7 +394,9 @@
403 ?NS_DISCO_INFO ->
404 process_iq_disco_info(From, Type, Lang, StateData);
405 ?NS_DISCO_ITEMS ->
406 - process_iq_disco_items(From, Type, Lang, StateData)
407 + process_iq_disco_items(From, Type, Lang, StateData);
408 + ?NS_CAPTCHA ->
409 + process_iq_captcha(From, Type, Lang, SubEl, StateData)
410 end,
411 {IQRes, NewStateData} =
412 case Res1 of
413 @@ -761,6 +766,30 @@
414 {empty, _} ->
415 {next_state, StateName, StateData}
416 end;
417 +handle_info({captcha_succeed, From}, normal_state, StateData) ->
418 + NewState = case ?DICT:find(From, StateData#state.robots) of
419 + {ok, {Nick, Packet}} ->
420 + Robots = ?DICT:store(From, passed, StateData#state.robots),
421 + add_new_user(From, Nick, Packet, StateData#state{robots=Robots});
422 + _ ->
423 + StateData
424 + end,
425 + {next_state, normal_state, NewState};
426 +handle_info({captcha_failed, From}, normal_state, StateData) ->
427 + NewState = case ?DICT:find(From, StateData#state.robots) of
428 + {ok, {Nick, Packet}} ->
429 + Robots = ?DICT:erase(From, StateData#state.robots),
430 + Err = jlib:make_error_reply(
431 + Packet, ?ERR_NOT_AUTHORIZED),
432 + ejabberd_router:route( % TODO: s/Nick/""/
433 + jlib:jid_replace_resource(
434 + StateData#state.jid, Nick),
435 + From, Err),
436 + StateData#state{robots=Robots};
437 + _ ->
438 + StateData
439 + end,
440 + {next_state, normal_state, NewState};
441 handle_info(_Info, StateName, StateData) ->
442 {next_state, StateName, StateData}.
443
444 @@ -1461,7 +1490,8 @@
445 From, Err),
446 StateData;
447 {_, _, _, Role} ->
448 - case check_password(ServiceAffiliation, Els, StateData) of
449 + case check_password(ServiceAffiliation, Affiliation,
450 + Els, From, StateData) of
451 true ->
452 NewState =
453 add_user_presence(
454 @@ -1494,7 +1524,8 @@
455 true ->
456 NewState#state{just_created = false};
457 false ->
458 - NewState
459 + Robots = ?DICT:erase(From, StateData#state.robots),
460 + NewState#state{robots = Robots}
461 end;
462 nopass ->
463 ErrText = "Password required to enter this room",
464 @@ -1505,6 +1536,29 @@
465 StateData#state.jid, Nick),
466 From, Err),
467 StateData;
468 + captcha_required ->
469 + ID = randoms:get_string(),
470 + SID = xml:get_attr_s("id", Attrs),
471 + RoomJID = StateData#state.jid,
472 + To = jlib:jid_replace_resource(RoomJID, Nick),
473 + case ejabberd_captcha:create_captcha(
474 + ID, SID, RoomJID, To, Lang, From) of
475 + {ok, CaptchaEls} ->
476 + MsgPkt = {xmlelement, "message", [{"id", ID}], CaptchaEls},
477 + Robots = ?DICT:store(From,
478 + {Nick, Packet}, StateData#state.robots),
479 + ejabberd_router:route(RoomJID, From, MsgPkt),
480 + StateData#state{robots = Robots};
481 + error ->
482 + ErrText = "Unable to generate a captcha",
483 + Err = jlib:make_error_reply(
484 + Packet, ?ERRT_INTERNAL_SERVER_ERROR(Lang, ErrText)),
485 + ejabberd_router:route( % TODO: s/Nick/""/
486 + jlib:jid_replace_resource(
487 + StateData#state.jid, Nick),
488 + From, Err),
489 + StateData
490 + end;
491 _ ->
492 ErrText = "Incorrect password",
493 Err = jlib:make_error_reply(
494 @@ -1517,13 +1571,13 @@
495 end
496 end.
497
498 -check_password(owner, _Els, _StateData) ->
499 +check_password(owner, _Affiliation, _Els, _From, _StateData) ->
500 %% Don't check pass if user is owner in MUC service (access_admin option)
501 true;
502 -check_password(_ServiceAffiliation, Els, StateData) ->
503 +check_password(_ServiceAffiliation, Affiliation, Els, From, StateData) ->
504 case (StateData#state.config)#config.password_protected of
505 false ->
506 - true;
507 + check_captcha(Affiliation, From, StateData);
508 true ->
509 Pass = extract_password(Els),
510 case Pass of
511 @@ -1539,6 +1593,19 @@
512 end
513 end.
514
515 +check_captcha(Affiliation, From, StateData) ->
516 + case (StateData#state.config)#config.captcha_protected of
517 + true when Affiliation == none ->
518 + case ?DICT:find(From, StateData#state.robots) of
519 + {ok, passed} ->
520 + true;
521 + _ ->
522 + captcha_required
523 + end;
524 + _ ->
525 + true
526 + end.
527 +
528 extract_password([]) ->
529 false;
530 extract_password([{xmlelement, _Name, Attrs, _SubEls} = El | Els]) ->
531 @@ -2713,6 +2780,9 @@
532 ?BOOLXFIELD("Make room members-only",
533 "muc#roomconfig_membersonly",
534 Config#config.members_only),
535 + ?BOOLXFIELD("Make room captcha protected",
536 + "captcha_protected",
537 + Config#config.captcha_protected),
538 ?BOOLXFIELD("Make room moderated",
539 "muc#roomconfig_moderatedroom",
540 Config#config.moderated),
541 @@ -2823,6 +2893,8 @@
542 ?SET_BOOL_XOPT(members_by_default, Val);
543 set_xoption([{"muc#roomconfig_membersonly", [Val]} | Opts], Config) ->
544 ?SET_BOOL_XOPT(members_only, Val);
545 +set_xoption([{"captcha_protected", [Val]} | Opts], Config) ->
546 + ?SET_BOOL_XOPT(captcha_protected, Val);
547 set_xoption([{"muc#roomconfig_allowinvites", [Val]} | Opts], Config) ->
548 ?SET_BOOL_XOPT(allow_user_invites, Val);
549 set_xoption([{"muc#roomconfig_passwordprotectedroom", [Val]} | Opts], Config) ->
550 @@ -2913,6 +2985,7 @@
551 ?CASE_CONFIG_OPT(members_only);
552 ?CASE_CONFIG_OPT(allow_user_invites);
553 ?CASE_CONFIG_OPT(password_protected);
554 + ?CASE_CONFIG_OPT(captcha_protected);
555 ?CASE_CONFIG_OPT(password);
556 ?CASE_CONFIG_OPT(anonymous);
557 ?CASE_CONFIG_OPT(logging);
558 @@ -2954,6 +3027,7 @@
559 ?MAKE_CONFIG_OPT(members_only),
560 ?MAKE_CONFIG_OPT(allow_user_invites),
561 ?MAKE_CONFIG_OPT(password_protected),
562 + ?MAKE_CONFIG_OPT(captcha_protected),
563 ?MAKE_CONFIG_OPT(password),
564 ?MAKE_CONFIG_OPT(anonymous),
565 ?MAKE_CONFIG_OPT(logging),
566 @@ -3074,6 +3148,17 @@
567 {error, ?ERR_FORBIDDEN}
568 end.
569
570 +process_iq_captcha(_From, get, _Lang, _SubEl, _StateData) ->
571 + {error, ?ERR_NOT_ALLOWED};
572 +
573 +process_iq_captcha(_From, set, _Lang, SubEl, StateData) ->
574 + case ejabberd_captcha:process_reply(SubEl) of
575 + ok ->
576 + {result, [], StateData};
577 + _ ->
578 + {error, ?ERR_NOT_ACCEPTABLE}
579 + end.
580 +
581 get_title(StateData) ->
582 case (StateData#state.config)#config.title of
583 "" ->
584 diff -urN ejabberd-2.0.4/src/web/ejabberd_http.erl ejabberd-2.0.4-new/src/web/ejabberd_http.erl
585 --- ejabberd-2.0.4/src/web/ejabberd_http.erl 2009-03-12 09:41:02.000000000 +0100
586 +++ ejabberd-2.0.4-new/src/web/ejabberd_http.erl 2009-03-14 10:57:34.000000000 +0100
587 @@ -106,6 +106,10 @@
588 {value, {request_handlers, H}} -> H;
589 false -> []
590 end ++
591 + case lists:member(captcha, Opts) of
592 + true -> [{["captcha"], ejabberd_captcha}];
593 + false -> []
594 + end ++
595 case lists:member(web_admin, Opts) of
596 true -> [{["admin"], ejabberd_web_admin}];
597 false -> []
598 Binary files ejabberd-2.0.4/tools/.DS_Store and ejabberd-2.0.4-new/tools/.DS_Store differ
599 diff -urN ejabberd-2.0.4/tools/captcha.sh ejabberd-2.0.4-new/tools/captcha.sh
600 --- ejabberd-2.0.4/tools/captcha.sh 1970-01-01 01:00:00.000000000 +0100
601 +++ ejabberd-2.0.4-new/tools/captcha.sh 2009-03-14 11:46:42.000000000 +0100
602 @@ -0,0 +1,21 @@
603 +#!/bin/sh
604 +
605 +SIGN=$(($RANDOM % 2))
606 +
607 +R1=$(($RANDOM % 20))
608 +R2=$(($RANDOM % 10 + 40))
609 +
610 +if [ $SIGN -eq "0" ]; then
611 + S1=$(( -1*($RANDOM % 20 + 50) ))
612 + S2=$(( $RANDOM % 20 + 50 ))
613 +else
614 + S2=$(( -1*($RANDOM % 20 + 50) ))
615 + S1=$(( $RANDOM % 20 + 50 ))
616 +fi
617 +
618 +convert -size 140x60 xc:white \
619 + -pointsize 30 -draw "text 20,30 '$1'" \
620 + -roll -$R2+$R1 -swirl $S1 \
621 + -roll +$R2-$R1 -swirl $S2 \
622 + +repage -resize 120x60 \
623 + -quality 90 -depth 8 png:-
624 --- ejabberd-2.0.5/ChangeLog~ 2009-04-01 19:23:52.000000000 +0400
625 +++ ejabberd-2.0.5/ChangeLog 2009-04-03 23:45:03.174979944 +0400
626 @@ -15,6 +15,15 @@
627 stanza (EJAB-300).
628 * src/ejabberd_c2s.erl: Likewise
629
630 +2009-03-13 Evgeniy Khramtsov <ekhramtsov@process-one.net>
631 +
632 + * src/ejabberd_captcha.erl: XEP-158 (CAPTCHA Forms).
633 + * src/ejabberd_config.erl: likewise.
634 + * src/ejabberd_sup.erl: likewise.
635 + * src/jlib.hrl: likewise.
636 + * src/web/ejabberd_http.erl: likewise.
637 + * src/mod_muc/mod_muc_room.erl: CAPTCHA support.
638 +
639 2009-03-10 Badlop <badlop@process-one.net>
640
641 * doc/release_notes_2.0.4.txt: Added file for new release

admin@koozali.org
ViewVC Help
Powered by ViewVC 1.2.1 RSS 2.0 feed