(* camlp4r ./pa_html.cmo *) (* $Id: forum.ml,v 4.37.2.1 2006/01/03 12:04:10 ddr Exp $ *) (* Copyright (c) 1998-2005 INRIA *) open Util; open Config; open Def; open Printf; type message = { m_time : string; m_ident : string; m_wizard : string; m_friend : string; m_email : string; m_access : string; m_subject : string; m_mess : string } ; value forum_file conf = Filename.concat (base_path [] (conf.bname ^ ".gwb")) "forum" ; (* Black list *) value match_strings regexp s = loop 0 0 where rec loop i j = if i == String.length regexp && j == String.length s then True else if i == String.length regexp then False else if j == String.length s then False else if regexp.[i] = s.[j] then loop (i + 1) (j + 1) else if regexp.[i] = '*' then if i + 1 == String.length regexp then True else if regexp.[i + 1] = s.[j] then loop (i + 2) (j + 1) else loop i (j + 1) else False ; value can_post conf = try let fname = List.assoc "forum_exclude_file" conf.base_env in let fname = Util.base_path [] fname in let ic = open_in fname in let rec loop () = match try Some (input_line ic) with [ End_of_file -> None ] with [ Some line -> if match_strings line conf.from then do { close_in ic; False } else loop () | None -> do { close_in ic; True } ] in loop () with [ Not_found | Sys_error _ -> True ] ; (* Print headers *) value get_var ic lab s = let len = String.length lab in if String.length s >= len && String.sub s 0 len = lab then let start = if String.length s > len && s.[len] = ' ' then len + 1 else len in (String.sub s start (String.length s - start), input_line ic) else ("", s) ; value sp2nbsp lim s = loop 0 0 where rec loop i len = if i >= String.length s then Buff.get len else if i > lim && String.length s > lim + 3 then Buff.get len ^ "..." else let len = match s.[i] with [ ' ' -> Buff.mstore len " " | x -> Buff.store len x ] in loop (i + 1) len ; value ndisp_items = 2; value change_item pd d = d.month <> pd.month; value print_one_header conf prec_date ndisp pos h = let (date, hour, ident, access, subject, beg_mess) = h in let ndisp = if date <> prec_date then do { let ndisp = match (prec_date, date) with [ (Dgreg pd _, Dgreg d _) -> if change_item d pd then if ndisp > 1 then do { if d.month <> pd.month then Wserver.wprint "
\n" else (); Wserver.wprint "
\n";
Wserver.wprint "%s\n" (secure m.m_ident);
if m.m_email <> "" then
let email = secure m.m_email in
Wserver.wprint " %s\n" email email
else ();
Wserver.wprint "
\n";
if m.m_subject <> "" then
Wserver.wprint "%s: %s\n
\n"
(capitale (header_txt conf 2)) (secure m.m_subject)
else ();
if m.m_access = "priv" then
Wserver.wprint "%s: %s\n
\n"
(capitale (transl conf "access")) (transl conf "private")
else ();
Wserver.wprint "%s\n" m.m_time;
Wserver.wprint "
| \n";
let mess =
loop True 0 0 where rec loop last_was_eoln len i =
if i = String.length m.m_mess then Buff.get len
else if m.m_mess.[i] = '\n' && last_was_eoln then
loop False (Buff.mstore len " \n") (i + 1) else loop (m.m_mess.[i] = '\n') (Buff.store len m.m_mess.[i]) (i + 1) in Wserver.wprint "%s\n" (string_with_macros conf True [] mess); if browser_doesnt_have_tables conf then () else Wserver.wprint " |
\n";
tag "form" "method=post action=\"%s\"" conf.command begin
Util.hidden_env conf;
Wserver.wprint "\n";
Wserver.wprint "\n" pos;
Wserver.wprint "\n"
(capitale
(transl_decline conf "delete" (message_txt conf 0)));
end;
}
else ();
trailer conf;
}
;
value print_forum_message conf base pos =
match get_message conf pos with
[ Some (m, _, next_pos, forum_length) ->
if m.m_access = "priv" && not conf.wizard && not conf.friend then
print_forum_headers conf base
else
print_one_forum_message conf m pos next_pos forum_length
| None -> print_forum_headers conf base ]
;
(* Print headers or message *)
value print conf base =
match p_getint conf.env "p" with
[ Some pos -> print_forum_message conf base pos
| None -> print_forum_headers conf base ]
;
(* Send a message *)
value print_var conf var name opt def_value =
tag "tr" "align=left" begin
stag "td" begin
Wserver.wprint "%s" name;
if opt then Wserver.wprint " (%s)" (transl conf "optional") else ();
end;
Wserver.wprint "\n";
stag "td" begin
Wserver.wprint "\n"
var def_value;
end;
Wserver.wprint "\n";
end
;
value print_add conf base =
let title _ =
Wserver.wprint "%s"
(capitale (transl_decline conf "add" (message_txt conf 0)))
in
if can_post conf then do {
header conf title;
print_link_to_welcome conf True;
tag "form" "method=post action=\"%s\"" conf.command begin
Util.hidden_env conf;
Wserver.wprint "\n";
tag "table" "border=%d" conf.border begin
print_var conf "Ident" (capitale (header_txt conf 0)) False
(if conf.username = "" then conf.user else conf.username);
print_var conf "Email" (capitale (header_txt conf 1)) True "";
print_var conf "Subject" (capitale (header_txt conf 2)) False "";
end;
html_p conf;
Wserver.wprint "%s
\n"
(capitale (Gutil.nominative (message_txt conf 0)));
stag "textarea" "name=Text rows=15 cols=70 wrap=soft" begin end;
Wserver.wprint "\n
\n";
if conf.wizard || conf.friend then
do {
Wserver.wprint "\n"
(transl conf "public");
Wserver.wprint "\n"
(transl conf "private");
}
else Wserver.wprint "\n";
end;
trailer conf;
}
else incorrect_request conf
;
value get conf key =
match p_getenv conf.env key with
[ Some v -> v
| None -> failwith (key ^ " unbound") ]
;
value forum_add conf base ident comm =
let email = String.lowercase (Gutil.strip_spaces (get conf "Email")) in
let subject = Gutil.strip_spaces (get conf "Subject") in
let access =
if conf.wizard || conf.friend then
match p_getenv conf.env "priv_acc" with
[ Some _ -> "priv"
| None -> "publ" ]
else "publ"
in
if ident <> "" && comm <> "" then
let fname = forum_file conf in
let tmp_fname = fname ^ "~" in
let oc = Secure.open_out tmp_fname in
try
let (hh, mm, ss) = conf.time in
do {
fprintf oc "Time: %04d-%02d-%02d %02d:%02d:%02d\n"
conf.today.year conf.today.month conf.today.day hh mm ss;
fprintf oc "From: %s\n" conf.from;
fprintf oc "Ident: %s\n" ident;
if (conf.wizard || conf.just_friend_wizard) && conf.user <> ""
then
fprintf oc "Wizard: %s\n" conf.user
else ();
if conf.friend && not conf.just_friend_wizard && conf.user <> "" then
fprintf oc "Friend: %s\n" conf.user
else ();
if email <> "" then fprintf oc "Email: %s\n" email else ();
fprintf oc "Access: %s\n" access;
let subject = if subject = "" then "-" else subject in
fprintf oc "Subject: %s\n" subject;
fprintf oc "Text:\n";
let rec loop i bol =
if i == String.length comm then ()
else do {
if bol then fprintf oc " " else ();
if comm.[i] <> '\r' then output_char oc comm.[i] else ();
loop (i + 1) (comm.[i] = '\n')
}
in
loop 0 True;
fprintf oc "\n\n";
match
try
Some (Secure.open_in_bin fname) with
[ Sys_error _ -> None ]
with
[ Some ic ->
do {
try while True do { output_char oc (input_char ic) } with
[ End_of_file -> () ];
close_in ic;
}
| _ -> () ];
close_out oc;
try Sys.remove fname with [ Sys_error _ -> () ];
Sys.rename tmp_fname fname;
}
with e ->
do {
try close_out oc with _ -> ();
try Sys.remove tmp_fname with [ Sys_error _ -> () ];
raise e
}
else ()
;
value print_add_ok conf base =
let ident = Gutil.strip_spaces (get conf "Ident") in
let comm = Gutil.strip_spaces (get conf "Text") in
if not (can_post conf) then incorrect_request conf
else if ident = "" || comm = "" then print conf base
else
let title _ =
Wserver.wprint "%s" (capitale (transl conf "message added"))
in
try
do {
forum_add conf base ident comm;
header conf title;
print_link_to_welcome conf True;
Wserver.wprint "%s\n" (commd conf)
(capitale (transl conf "database forum"));
trailer conf;
}
with
[ Update.ModErr -> () ]
;
(* Deleting a message *)
value internal_error conf base =
let title _ = Wserver.wprint "%s" (capitale (transl conf "error")) in
do {
rheader conf title;
Wserver.wprint "internal error\n";
trailer conf;
raise Update.ModErr
}
;
value forum_del conf base pos next_pos =
let fname = forum_file conf in
let tmp_fname = fname ^ "~" in
match
try Some (Secure.open_in_bin fname) with [ Sys_error _ -> None ]
with
[ Some ic ->
let oc = Secure.open_out tmp_fname in
let len = in_channel_length ic in
let pos = len - pos in
do {
loop 0 where rec loop i =
if i = len then ()
else
let c = input_char ic in
do {
if i < pos || i >= pos + 4 then output_char oc c
else output_char oc '*';
loop (i + 1);
};
close_in ic;
close_out oc;
try Sys.remove fname with [ Sys_error _ -> () ];
Sys.rename tmp_fname fname;
}
| None -> internal_error conf base ]
;
value print_del_ok conf base =
let title _ =
Wserver.wprint "%s" (capitale (transl conf "message deleted"))
in
do {
header conf title;
print_link_to_welcome conf True;
Wserver.wprint "%s\n" (commd conf)
(capitale (transl conf "database forum"));
trailer conf;
}
;
value delete_forum_message conf base pos =
match get_message conf pos with
[ Some (m, _, next_pos, forum_length) ->
if conf.wizard && conf.user <> "" && m.m_wizard = conf.user &&
passwd_in_file conf
then
try
do {
forum_del conf base pos next_pos;
print_del_ok conf base;
}
with
[ Update.ModErr -> () ]
else print_forum_headers conf base
| None -> print_forum_headers conf base ]
;
value print_del conf base =
match p_getint conf.env "p" with
[ Some pos -> delete_forum_message conf base pos
| None -> print_forum_headers conf base ]
;