25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-12-22 17:28:25 +01:00

* src/mod_muc/mod_muc_log.erl: MUC log files options: plaintext

format; filename with only room name (EJAB-596)
* doc/guide.tex: Document both options
* doc/guide.html: Likewise

SVN Revision: 1531
This commit is contained in:
Badlop 2008-08-18 19:08:30 +00:00
parent 4ae1bda33f
commit e37723f4a2
4 changed files with 182 additions and 100 deletions

View File

@ -1,5 +1,10 @@
2008-08-18 Badlop <badlop@process-one.net> 2008-08-18 Badlop <badlop@process-one.net>
* src/mod_muc/mod_muc_log.erl: MUC log files options: plaintext
format; filename with only room name (EJAB-596)
* doc/guide.tex: Document both options
* doc/guide.html: Likewise
* src/mod_register.erl: Change password using mod_register always * src/mod_register.erl: Change password using mod_register always
returns success regardless of real result (EJAB-723) returns success regardless of real result (EJAB-723)
* src/ejabberd_auth.erl: Likewise * src/ejabberd_auth.erl: Likewise

View File

@ -2184,26 +2184,38 @@ file or if they need to use the embedded CSS file. Allowed values are
include the embedded CSS code. With the latter, you can specify the URL of the include the embedded CSS code. With the latter, you can specify the URL of the
custom CSS file (for example: &#X2018;http://example.com/my.css&#X2019;). The default value custom CSS file (for example: &#X2018;http://example.com/my.css&#X2019;). The default value
is <TT>false</TT>. is <TT>false</TT>.
</DD><DT CLASS="dt-description"><B><TT>dirname</TT></B></DT><DD CLASS="dd-description">
Allows to configure the name of the room directory.
Allowed values are <TT>room_jid</TT> and <TT>room_name</TT>.
With the first value, the room directory name will be the full room JID.
With the latter, the room directory name will be only the room name,
not including the MUC service name.
The default value is <TT>room_jid</TT>.
</DD><DT CLASS="dt-description"><B><TT>dirtype</TT></B></DT><DD CLASS="dd-description"> </DD><DT CLASS="dt-description"><B><TT>dirtype</TT></B></DT><DD CLASS="dd-description">
The type of the created directories can be specified with this option. Allowed The type of the created directories can be specified with this option. Allowed
values are <TT>subdirs</TT> and <TT>plain</TT>. With the first value, values are <TT>subdirs</TT> and <TT>plain</TT>. With the first value,
subdirectories are created for each year and month. With the latter, the subdirectories are created for each year and month. With the latter, the
names of the log files contain the full date, and there are no subdirectories. names of the log files contain the full date, and there are no subdirectories.
The default value is <TT>subdirs</TT>. The default value is <TT>subdirs</TT>.
</DD><DT CLASS="dt-description"><B><TT>file_format</TT></B></DT><DD CLASS="dd-description">
Define the format of the log files:
<TT>html</TT> stores in HTML format,
<TT>plaintext</TT> stores in plain text.
The default value is <TT>html</TT>.
</DD><DT CLASS="dt-description"><B><TT>outdir</TT></B></DT><DD CLASS="dd-description"> </DD><DT CLASS="dt-description"><B><TT>outdir</TT></B></DT><DD CLASS="dd-description">
This option sets the full path to the directory in which the HTML files should This option sets the full path to the directory in which the HTML files should
be stored. Make sure the <TT>ejabberd</TT> daemon user has write access on that be stored. Make sure the <TT>ejabberd</TT> daemon user has write access on that
directory. The default value is <TT>"www/muc"</TT>. directory. The default value is <TT>"www/muc"</TT>.
</DD><DT CLASS="dt-description"><B><TT>timezone</TT></B></DT><DD CLASS="dd-description">
The time zone for the logs is configurable with this option. Allowed values
are <TT>local</TT> and <TT>universal</TT>. With the first value, the local time,
as reported to Erlang by the operating system, will be used. With the latter,
GMT/UTC time will be used. The default value is <TT>local</TT>.
</DD><DT CLASS="dt-description"><B><TT>spam_prevention</TT></B></DT><DD CLASS="dd-description"> </DD><DT CLASS="dt-description"><B><TT>spam_prevention</TT></B></DT><DD CLASS="dd-description">
To prevent spam, the <TT>spam_prevention</TT> option adds a special attribute To prevent spam, the <TT>spam_prevention</TT> option adds a special attribute
to links that prevent their indexation by search engines. The default value to links that prevent their indexation by search engines. The default value
is <TT>true</TT>, which mean that nofollow attributes will be added to user is <TT>true</TT>, which mean that nofollow attributes will be added to user
submitted links. submitted links.
</DD><DT CLASS="dt-description"><B><TT>timezone</TT></B></DT><DD CLASS="dd-description">
The time zone for the logs is configurable with this option. Allowed values
are <TT>local</TT> and <TT>universal</TT>. With the first value, the local time,
as reported to Erlang by the operating system, will be used. With the latter,
GMT/UTC time will be used. The default value is <TT>local</TT>.
</DD><DT CLASS="dt-description"><B><TT>top_link</TT></B></DT><DD CLASS="dd-description"> </DD><DT CLASS="dt-description"><B><TT>top_link</TT></B></DT><DD CLASS="dd-description">
With this option you can customize the link on the top right corner of each With this option you can customize the link on the top right corner of each
log file. The syntax of this option is <TT>{"URL", "Text"}</TT>. The default log file. The syntax of this option is <TT>{"URL", "Text"}</TT>. The default
@ -2225,6 +2237,7 @@ time zone will be GMT/UTC. Finally, the top link will be
{access_log, muc}, {access_log, muc},
{cssfile, "http://example.com/my.css"}, {cssfile, "http://example.com/my.css"},
{dirtype, plain}, {dirtype, plain},
{dirname, room_jid},
{outdir, "/var/www/muclogs"}, {outdir, "/var/www/muclogs"},
{timezone, universal}, {timezone, universal},
{spam_prevention, true}, {spam_prevention, true},

View File

@ -2828,26 +2828,38 @@ Options:
include the embedded CSS code. With the latter, you can specify the URL of the include the embedded CSS code. With the latter, you can specify the URL of the
custom CSS file (for example: `http://example.com/my.css'). The default value custom CSS file (for example: `http://example.com/my.css'). The default value
is \term{false}. is \term{false}.
\titem{dirname}\ind{options!dirname}
Allows to configure the name of the room directory.
Allowed values are \term{room\_jid} and \term{room\_name}.
With the first value, the room directory name will be the full room JID.
With the latter, the room directory name will be only the room name,
not including the MUC service name.
The default value is \term{room\_jid}.
\titem{dirtype}\ind{options!dirtype} \titem{dirtype}\ind{options!dirtype}
The type of the created directories can be specified with this option. Allowed The type of the created directories can be specified with this option. Allowed
values are \term{subdirs} and \term{plain}. With the first value, values are \term{subdirs} and \term{plain}. With the first value,
subdirectories are created for each year and month. With the latter, the subdirectories are created for each year and month. With the latter, the
names of the log files contain the full date, and there are no subdirectories. names of the log files contain the full date, and there are no subdirectories.
The default value is \term{subdirs}. The default value is \term{subdirs}.
\titem{file\_format}\ind{options!file\_format}
Define the format of the log files:
\term{html} stores in HTML format,
\term{plaintext} stores in plain text.
The default value is \term{html}.
\titem{outdir}\ind{options!outdir} \titem{outdir}\ind{options!outdir}
This option sets the full path to the directory in which the HTML files should This option sets the full path to the directory in which the HTML files should
be stored. Make sure the \ejabberd{} daemon user has write access on that be stored. Make sure the \ejabberd{} daemon user has write access on that
directory. The default value is \term{"www/muc"}. directory. The default value is \term{"www/muc"}.
\titem{timezone}\ind{options!timezone}
The time zone for the logs is configurable with this option. Allowed values
are \term{local} and \term{universal}. With the first value, the local time,
as reported to Erlang by the operating system, will be used. With the latter,
GMT/UTC time will be used. The default value is \term{local}.
\titem{spam\_prevention}\ind{options!spam\_prevention} \titem{spam\_prevention}\ind{options!spam\_prevention}
To prevent spam, the \term{spam\_prevention} option adds a special attribute To prevent spam, the \term{spam\_prevention} option adds a special attribute
to links that prevent their indexation by search engines. The default value to links that prevent their indexation by search engines. The default value
is \term{true}, which mean that nofollow attributes will be added to user is \term{true}, which mean that nofollow attributes will be added to user
submitted links. submitted links.
\titem{timezone}\ind{options!timezone}
The time zone for the logs is configurable with this option. Allowed values
are \term{local} and \term{universal}. With the first value, the local time,
as reported to Erlang by the operating system, will be used. With the latter,
GMT/UTC time will be used. The default value is \term{local}.
\titem{top\_link}\ind{options!top\_link} \titem{top\_link}\ind{options!top\_link}
With this option you can customize the link on the top right corner of each With this option you can customize the link on the top right corner of each
log file. The syntax of this option is \term{\{"URL", "Text"\}}. The default log file. The syntax of this option is \term{\{"URL", "Text"\}}. The default
@ -2872,6 +2884,7 @@ Examples:
{access_log, muc}, {access_log, muc},
{cssfile, "http://example.com/my.css"}, {cssfile, "http://example.com/my.css"},
{dirtype, plain}, {dirtype, plain},
{dirname, room_jid},
{outdir, "/var/www/muclogs"}, {outdir, "/var/www/muclogs"},
{timezone, universal}, {timezone, universal},
{spam_prevention, true}, {spam_prevention, true},

View File

@ -52,6 +52,8 @@
-record(state, {host, -record(state, {host,
out_dir, out_dir,
dir_type, dir_type,
dir_name,
file_format,
css_file, css_file,
access, access,
lang, lang,
@ -113,6 +115,8 @@ check_access_log(Host, From) ->
init([Host, Opts]) -> init([Host, Opts]) ->
OutDir = gen_mod:get_opt(outdir, Opts, "www/muc"), OutDir = gen_mod:get_opt(outdir, Opts, "www/muc"),
DirType = gen_mod:get_opt(dirtype, Opts, subdirs), DirType = gen_mod:get_opt(dirtype, Opts, subdirs),
DirName = gen_mod:get_opt(dirname, Opts, room_jid),
FileFormat = gen_mod:get_opt(file_format, Opts, html), % Allowed values: html|plaintext
CSSFile = gen_mod:get_opt(cssfile, Opts, false), CSSFile = gen_mod:get_opt(cssfile, Opts, false),
AccessLog = gen_mod:get_opt(access_log, Opts, muc_admin), AccessLog = gen_mod:get_opt(access_log, Opts, muc_admin),
Timezone = gen_mod:get_opt(timezone, Opts, local), Timezone = gen_mod:get_opt(timezone, Opts, local),
@ -129,6 +133,8 @@ init([Host, Opts]) ->
{ok, #state{host = Host, {ok, #state{host = Host,
out_dir = OutDir, out_dir = OutDir,
dir_type = DirType, dir_type = DirType,
dir_name = DirName,
file_format = FileFormat,
css_file = CSSFile, css_file = CSSFile,
access = AccessLog, access = AccessLog,
lang = Lang, lang = Lang,
@ -231,10 +237,10 @@ add_to_log2(kickban, {Nick, Reason, Code}, Room, Opts, State) ->
%%---------------------------------------------------------------------- %%----------------------------------------------------------------------
%% Core %% Core
build_filename_string(TimeStamp, OutDir, RoomJID, DirType) -> build_filename_string(TimeStamp, OutDir, RoomJID, DirType, DirName, FileFormat) ->
{{Year, Month, Day}, _Time} = TimeStamp, {{Year, Month, Day}, _Time} = TimeStamp,
% Directory and file names %% Directory and file names
{Dir, Filename, Rel} = {Dir, Filename, Rel} =
case DirType of case DirType of
subdirs -> subdirs ->
@ -248,55 +254,75 @@ build_filename_string(TimeStamp, OutDir, RoomJID, DirType) ->
[Year, Month, Day])), [Year, Month, Day])),
{"", Date, "."} {"", Date, "."}
end, end,
Fd = filename:join([OutDir, RoomJID, Dir]),
Fn = filename:join([Fd, Filename ++ ".html"]), RoomString = case DirName of
Fnrel = filename:join([Rel, Dir, Filename ++ ".html"]), room_jid -> RoomJID;
room_name -> get_room_name(RoomJID)
end,
Extension = case FileFormat of
html -> ".html";
plaintext -> ".txt"
end,
Fd = filename:join([OutDir, RoomString, Dir]),
Fn = filename:join([Fd, Filename ++ Extension]),
Fnrel = filename:join([Rel, Dir, Filename ++ Extension]),
{Fd, Fn, Fnrel}. {Fd, Fn, Fnrel}.
% calculate day before get_room_name(RoomJID) ->
JID = jlib:string_to_jid(RoomJID),
JID#jid.user.
%% calculate day before
get_timestamp_daydiff(TimeStamp, Daydiff) -> get_timestamp_daydiff(TimeStamp, Daydiff) ->
{Date1, HMS} = TimeStamp, {Date1, HMS} = TimeStamp,
Date2 = calendar:gregorian_days_to_date( Date2 = calendar:gregorian_days_to_date(
calendar:date_to_gregorian_days(Date1) + Daydiff), calendar:date_to_gregorian_days(Date1) + Daydiff),
{Date2, HMS}. {Date2, HMS}.
% Try to close the previous day log, if it exists %% Try to close the previous day log, if it exists
close_previous_log(Fn, Images_dir) -> close_previous_log(Fn, Images_dir, FileFormat) ->
case file:read_file_info(Fn) of case file:read_file_info(Fn) of
{ok, _} -> {ok, _} ->
{ok, F} = file:open(Fn, [append]), {ok, F} = file:open(Fn, [append]),
%fw(F, "<div class=\"legend\">ejabberd/mod_muc log<span class=\"w3c\">"), write_last_lines(F, Images_dir, FileFormat),
fw(F, "<div class=\"legend\">"),
fw(F, " <a href=\"http://www.ejabberd.im\"><img style=\"border:0\" src=\"~s/powered-by-ejabberd.png\" alt=\"Powered by ejabberd\"/></a>", [Images_dir]),
fw(F, " <a href=\"http://www.erlang.org/\"><img style=\"border:0\" src=\"~s/powered-by-erlang.png\" alt=\"Powered by Erlang\"/></a>", [Images_dir]),
fw(F, "<span class=\"w3c\">"),
fw(F, " <a href=\"http://validator.w3.org/check?uri=referer\"><img style=\"border:0;width:88px;height:31px\" src=\"~s/valid-xhtml10.png\" alt=\"Valid XHTML 1.0 Transitional\" /></a>", [Images_dir]),
fw(F, " <a href=\"http://jigsaw.w3.org/css-validator/\"><img style=\"border:0;width:88px;height:31px\" src=\"~s/vcss.png\" alt=\"Valid CSS!\"/></a>", [Images_dir]),
fw(F, "</span></div></body></html>"),
file:close(F); file:close(F);
_ -> ok _ -> ok
end. end.
write_last_lines(_, _, plaintext) ->
ok;
write_last_lines(F, Images_dir, _FileFormat) ->
%%fw(F, "<div class=\"legend\">ejabberd/mod_muc log<span class=\"w3c\">"),
fw(F, "<div class=\"legend\">"),
fw(F, " <a href=\"http://www.ejabberd.im\"><img style=\"border:0\" src=\"~s/powered-by-ejabberd.png\" alt=\"Powered by ejabberd\"/></a>", [Images_dir]),
fw(F, " <a href=\"http://www.erlang.org/\"><img style=\"border:0\" src=\"~s/powered-by-erlang.png\" alt=\"Powered by Erlang\"/></a>", [Images_dir]),
fw(F, "<span class=\"w3c\">"),
fw(F, " <a href=\"http://validator.w3.org/check?uri=referer\"><img style=\"border:0;width:88px;height:31px\" src=\"~s/valid-xhtml10.png\" alt=\"Valid XHTML 1.0 Transitional\" /></a>", [Images_dir]),
fw(F, " <a href=\"http://jigsaw.w3.org/css-validator/\"><img style=\"border:0;width:88px;height:31px\" src=\"~s/vcss.png\" alt=\"Valid CSS!\"/></a>", [Images_dir]),
fw(F, "</span></div></body></html>").
add_message_to_log(Nick1, Message, RoomJID, Opts, State) -> add_message_to_log(Nick1, Message, RoomJID, Opts, State) ->
Nick = htmlize(Nick1),
#state{out_dir = OutDir, #state{out_dir = OutDir,
dir_type = DirType, dir_type = DirType,
dir_name = DirName,
file_format = FileFormat,
css_file = CSSFile, css_file = CSSFile,
lang = Lang, lang = Lang,
timezone = Timezone, timezone = Timezone,
spam_prevention = NoFollow, spam_prevention = NoFollow,
top_link = TopLink} = State, top_link = TopLink} = State,
Room = get_room_info(RoomJID, Opts), Room = get_room_info(RoomJID, Opts),
Nick = htmlize(Nick1, FileFormat),
Nick2 = htmlize("<"++Nick1++">", FileFormat),
Now = now(), Now = now(),
TimeStamp = case Timezone of TimeStamp = case Timezone of
local -> calendar:now_to_local_time(Now); local -> calendar:now_to_local_time(Now);
universal -> calendar:now_to_universal_time(Now) universal -> calendar:now_to_universal_time(Now)
end, end,
{Fd, Fn, _Dir} = build_filename_string(TimeStamp, OutDir, Room#room.jid, DirType), {Fd, Fn, _Dir} = build_filename_string(TimeStamp, OutDir, Room#room.jid, DirType, DirName, FileFormat),
{Date, Time} = TimeStamp, {Date, Time} = TimeStamp,
% Open file, create if it does not exist, create parent dirs if needed %% Open file, create if it does not exist, create parent dirs if needed
case file:read_file_info(Fn) of case file:read_file_info(Fn) of
{ok, _} -> {ok, _} ->
{ok, F} = file:open(Fn, [append]); {ok, F} = file:open(Fn, [append]);
@ -308,32 +334,32 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) ->
TimeStampYesterday = get_timestamp_daydiff(TimeStamp, -1), TimeStampYesterday = get_timestamp_daydiff(TimeStamp, -1),
{_FdYesterday, FnYesterday, DatePrev} = {_FdYesterday, FnYesterday, DatePrev} =
build_filename_string( build_filename_string(
TimeStampYesterday, OutDir, Room#room.jid, DirType), TimeStampYesterday, OutDir, Room#room.jid, DirType, DirName, FileFormat),
TimeStampTomorrow = get_timestamp_daydiff(TimeStamp, 1), TimeStampTomorrow = get_timestamp_daydiff(TimeStamp, 1),
{_FdTomorrow, _FnTomorrow, DateNext} = {_FdTomorrow, _FnTomorrow, DateNext} =
build_filename_string( build_filename_string(
TimeStampTomorrow, OutDir, Room#room.jid, DirType), TimeStampTomorrow, OutDir, Room#room.jid, DirType, DirName, FileFormat),
HourOffset = calc_hour_offset(TimeStamp), HourOffset = calc_hour_offset(TimeStamp),
put_header(F, Room, Datestring, CSSFile, Lang, put_header(F, Room, Datestring, CSSFile, Lang,
HourOffset, DatePrev, DateNext, TopLink), HourOffset, DatePrev, DateNext, TopLink, FileFormat),
Images_dir = filename:join([OutDir, "images"]), Images_dir = filename:join([OutDir, "images"]),
file:make_dir(Images_dir), file:make_dir(Images_dir),
create_image_files(Images_dir), create_image_files(Images_dir),
Images_url = case DirType of Images_url = case DirType of
subdirs -> "../../../images"; subdirs -> "../../../images";
plain -> "../images" plain -> "../images"
end, end,
close_previous_log(FnYesterday, Images_url) close_previous_log(FnYesterday, Images_url, FileFormat)
end, end,
% Build message %% Build message
Text = case Message of Text = case Message of
roomconfig_change -> roomconfig_change ->
RoomConfig = roomconfig_to_string(Room#room.config, Lang), RoomConfig = roomconfig_to_string(Room#room.config, Lang, FileFormat),
put_room_config(F, RoomConfig, Lang), put_room_config(F, RoomConfig, Lang, FileFormat),
io_lib:format("<font class=\"mrcm\">~s</font><br/>", io_lib:format("<font class=\"mrcm\">~s</font><br/>",
[?T("Chatroom configuration modified")]); [?T("Chatroom configuration modified")]);
join -> join ->
@ -344,19 +370,19 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) ->
[Nick, ?T("leaves the room")]); [Nick, ?T("leaves the room")]);
{leave, Reason} -> {leave, Reason} ->
io_lib:format("<font class=\"ml\">~s ~s: ~s</font><br/>", io_lib:format("<font class=\"ml\">~s ~s: ~s</font><br/>",
[Nick, ?T("leaves the room"), htmlize(Reason,NoFollow)]); [Nick, ?T("leaves the room"), htmlize(Reason,NoFollow,FileFormat)]);
{kickban, "301", ""} -> {kickban, "301", ""} ->
io_lib:format("<font class=\"mb\">~s ~s</font><br/>", io_lib:format("<font class=\"mb\">~s ~s</font><br/>",
[Nick, ?T("has been banned")]); [Nick, ?T("has been banned")]);
{kickban, "301", Reason} -> {kickban, "301", Reason} ->
io_lib:format("<font class=\"mb\">~s ~s: ~s</font><br/>", io_lib:format("<font class=\"mb\">~s ~s: ~s</font><br/>",
[Nick, ?T("has been banned"), htmlize(Reason)]); [Nick, ?T("has been banned"), htmlize(Reason,FileFormat)]);
{kickban, "307", ""} -> {kickban, "307", ""} ->
io_lib:format("<font class=\"mk\">~s ~s</font><br/>", io_lib:format("<font class=\"mk\">~s ~s</font><br/>",
[Nick, ?T("has been kicked")]); [Nick, ?T("has been kicked")]);
{kickban, "307", Reason} -> {kickban, "307", Reason} ->
io_lib:format("<font class=\"mk\">~s ~s: ~s</font><br/>", io_lib:format("<font class=\"mk\">~s ~s: ~s</font><br/>",
[Nick, ?T("has been kicked"), htmlize(Reason)]); [Nick, ?T("has been kicked"), htmlize(Reason,FileFormat)]);
{kickban, "321", ""} -> {kickban, "321", ""} ->
io_lib:format("<font class=\"mk\">~s ~s</font><br/>", io_lib:format("<font class=\"mk\">~s ~s</font><br/>",
[Nick, ?T("has been kicked because of an affiliation change")]); [Nick, ?T("has been kicked because of an affiliation change")]);
@ -368,18 +394,18 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) ->
[Nick, ?T("has been kicked because of a system shutdown")]); [Nick, ?T("has been kicked because of a system shutdown")]);
{nickchange, OldNick} -> {nickchange, OldNick} ->
io_lib:format("<font class=\"mnc\">~s ~s ~s</font><br/>", io_lib:format("<font class=\"mnc\">~s ~s ~s</font><br/>",
[htmlize(OldNick), ?T("is now known as"), Nick]); [htmlize(OldNick,FileFormat), ?T("is now known as"), Nick]);
{subject, T} -> {subject, T} ->
io_lib:format("<font class=\"msc\">~s~s~s</font><br/>", io_lib:format("<font class=\"msc\">~s~s~s</font><br/>",
[Nick, ?T(" has set the subject to: "), htmlize(T,NoFollow)]); [Nick, ?T(" has set the subject to: "), htmlize(T,NoFollow,FileFormat)]);
{body, T} -> {body, T} ->
case regexp:first_match(T, "^/me\s") of case regexp:first_match(T, "^/me\s") of
{match, _, _} -> {match, _, _} ->
io_lib:format("<font class=\"mne\">~s ~s</font><br/>", io_lib:format("<font class=\"mne\">~s ~s</font><br/>",
[Nick, string:substr(htmlize(T), 5)]); [Nick, string:substr(htmlize(T,FileFormat), 5)]);
nomatch -> nomatch ->
io_lib:format("<font class=\"mn\">&lt;~s&gt;</font> ~s<br/>", io_lib:format("<font class=\"mn\">~s</font> ~s<br/>",
[Nick, htmlize(T,NoFollow)]) [Nick2, htmlize(T,NoFollow,FileFormat)])
end end
end, end,
{Hour, Minute, Second} = Time, {Hour, Minute, Second} = Time,
@ -388,11 +414,11 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) ->
{_, _, Microsecs} = Now, {_, _, Microsecs} = Now,
STimeUnique = io_lib:format("~s.~w", [STime, Microsecs]), STimeUnique = io_lib:format("~s.~w", [STime, Microsecs]),
% Write message %% Write message
file:write(F, io_lib:format("<a id=\"~s\" name=\"~s\" href=\"#~s\" class=\"ts\">[~s]</a> ~s~n", fw(F, io_lib:format("<a id=\"~s\" name=\"~s\" href=\"#~s\" class=\"ts\">[~s]</a> ",
[STimeUnique, STimeUnique, STimeUnique, STime, Text])), [STimeUnique, STimeUnique, STimeUnique, STime]) ++ Text, FileFormat),
% Close file %% Close file
file:close(F), file:close(F),
ok. ok.
@ -443,13 +469,13 @@ make_dir_rec(Dir) ->
end. end.
% {ok, F1}=file:open("valid-xhtml10.png", [read]). %% {ok, F1}=file:open("valid-xhtml10.png", [read]).
% {ok, F1b}=file:read(F1, 1000000). %% {ok, F1b}=file:read(F1, 1000000).
% c("../../ejabberd/src/jlib.erl"). %% c("../../ejabberd/src/jlib.erl").
% jlib:encode_base64(F1b). %% jlib:encode_base64(F1b).
image_base64("powered-by-erlang.png") -> image_base64("powered-by-erlang.png") ->
"iVBORw0KGgoAAAANSUhEUgAAAGUAAAAfCAYAAAD+xQNoAAADN0lEQVRo3u1a" "iVBORw0KGgoAAAANSUhEUgAAAGUAAAAfCAYAAAD+xQNoAAADN0lEQVRo3u1a"
"P0waURz+rjGRRQ+nUyRCYmJyDPTapDARaSIbTUjt1gVSh8ZW69aBAR0cWLSx" "P0waURz+rjGRRQ+nUyRCYmJyDPTapDARaSIbTUjt1gVSh8ZW69aBAR0cWLSx"
"CXWp59LR1jbdqKnGxoQuRZZrSYyHEVM6iZMbHewROA7u3fHvkr5vOn737vcu" "CXWp59LR1jbdqKnGxoQuRZZrSYyHEVM6iZMbHewROA7u3fHvkr5vOn737vcu"
"33ffu9/vcQz+gef5Cij6CkmSGABgFEH29r5SVvqIsTEOHo8HkiQxDBXEOjg9" "33ffu9/vcQz+gef5Cij6CkmSGABgFEH29r5SVvqIsTEOHo8HkiQxDBXEOjg9"
@ -471,7 +497,7 @@ image_base64("powered-by-erlang.png") ->
"KF/d/wX3cJvREzl1vAAAAABJRU5ErkJggg=="; "KF/d/wX3cJvREzl1vAAAAABJRU5ErkJggg==";
image_base64("valid-xhtml10.png") -> image_base64("valid-xhtml10.png") ->
"iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAAEjEcpEAAACiFBMVEUAAADe" "iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAAEjEcpEAAACiFBMVEUAAADe"
"5+fOezmtra3ejEKlhELvvWO9WlrehELOe3vepaWclHvetVLGc3PerVKcCAj3" "5+fOezmtra3ejEKlhELvvWO9WlrehELOe3vepaWclHvetVLGc3PerVKcCAj3"
"vVqUjHOUe1JjlL0xOUpjjL2UAAC91ueMrc7vrVKlvdbW3u+EpcbO3ufO1ucY" "vVqUjHOUe1JjlL0xOUpjjL2UAAC91ueMrc7vrVKlvdbW3u+EpcbO3ufO1ucY"
"WpSMKQi9SiF7e3taWkoQEAiMczkQSoxaUkpzc3O1lEoICACEazEhGAgIAACE" "WpSMKQi9SiF7e3taWkoQEAiMczkQSoxaUkpzc3O1lEoICACEazEhGAgIAACE"
@ -527,7 +553,7 @@ image_base64("valid-xhtml10.png") ->
"QZ+RYfpNE/4Xosmq7jsZAJsAAAAASUVORK5CYII="; "QZ+RYfpNE/4Xosmq7jsZAJsAAAAASUVORK5CYII=";
image_base64("vcss.png") -> image_base64("vcss.png") ->
"iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAABUFvrSAAABKVBMVEUAAAAj" "iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAABUFvrSAAABKVBMVEUAAAAj"
"Ix8MR51ZVUqAdlmdnZ3ejEWLDAuNjY1kiMG0n2d9fX19Ghfrp1FtbW3y39+3" "Ix8MR51ZVUqAdlmdnZ3ejEWLDAuNjY1kiMG0n2d9fX19Ghfrp1FtbW3y39+3"
"Ph6lIRNdXV2qJBFcVUhcVUhPT0/dsmpUfLr57+/u7u4/PDWZAACZAADOp1Gd" "Ph6lIRNdXV2qJBFcVUhcVUhPT0/dsmpUfLr57+/u7u4/PDWZAACZAADOp1Gd"
"GxG+SyTgvnNdSySzk16+mkuxw+BOS0BOS0DOzs7MzMy4T09RRDwsJBG+vr73" "GxG+SyTgvnNdSySzk16+mkuxw+BOS0BOS0DOzs7MzMy4T09RRDwsJBG+vr73"
@ -555,7 +581,7 @@ image_base64("vcss.png") ->
"AElFTkSuQmCC"; "AElFTkSuQmCC";
image_base64("powered-by-ejabberd.png") -> image_base64("powered-by-ejabberd.png") ->
"iVBORw0KGgoAAAANSUhEUgAAAGUAAAAfCAMAAADJG/NaAAAAw1BMVEUAAAAj" "iVBORw0KGgoAAAANSUhEUgAAAGUAAAAfCAMAAADJG/NaAAAAw1BMVEUAAAAj"
"BgYtBAM5AwFCAAAYGAJNAABcAABIDQ5qAAAoJRV7AACFAAAoKSdJHByLAAAw" "BgYtBAM5AwFCAAAYGAJNAABcAABIDQ5qAAAoJRV7AACFAAAoKSdJHByLAAAw"
"Lwk1NQA1MzFJKyo4NxtDQQBEQT5KSCxSTgBSUBlgQ0JYSEpZWQJPUU5hYABb" "Lwk1NQA1MzFJKyo4NxtDQQBEQT5KSCxSTgBSUBlgQ0JYSEpZWQJPUU5hYABb"
"W0ZiYClcW1poaCVwbQRpaDhzYWNsakhuZ2VrbFZ8dwCEgAB3dnd4d2+OjACD" "W0ZiYClcW1poaCVwbQRpaDhzYWNsakhuZ2VrbFZ8dwCEgAB3dnd4d2+OjACD"
@ -579,27 +605,43 @@ image_base64("powered-by-ejabberd.png") ->
"AElFTkSuQmCC". "AElFTkSuQmCC".
create_image_files(Images_dir) -> create_image_files(Images_dir) ->
Filenames = [ Filenames = ["powered-by-ejabberd.png",
"powered-by-ejabberd.png", "powered-by-erlang.png",
"powered-by-erlang.png", "valid-xhtml10.png",
"valid-xhtml10.png", "vcss.png"
"vcss.png" ],
], lists:foreach(
lists:foreach( fun(Filename) ->
fun(Filename) -> Filename_full = filename:join([Images_dir, Filename]),
Filename_full = filename:join([Images_dir, Filename]), {ok, F} = file:open(Filename_full, [write]),
{ok, F} = file:open(Filename_full, [write]), Image = jlib:decode_base64(image_base64(Filename)),
Image = jlib:decode_base64(image_base64(Filename)), io:format(F, "~s", [Image]),
io:format(F, "~s", [Image]), file:close(F)
file:close(F) end,
end, Filenames),
Filenames), ok.
ok.
fw(F, S, O) -> io:format(F, S ++ "~n", O). fw(F, S) -> fw(F, S, [], html).
fw(F, S) -> fw(F, S, []).
put_header(F, Room, Date, CSSFile, Lang, Hour_offset, Date_prev, Date_next, Top_link) -> fw(F, S, O) when is_list(O) ->
fw(F, S, O, html);
fw(F, S, FileFormat) when is_atom(FileFormat) ->
fw(F, S, [], FileFormat).
fw(F, S, O, FileFormat) ->
S1 = io_lib:format(S ++ "~n", O),
S2 = case FileFormat of
html ->
S1;
plaintext ->
{ok, Res, _} = regexp:gsub(S1, "<[^>]*>", ""),
Res
end,
io:format(F, S2, []).
put_header(_, _, _, _, _, _, _, _, _, plaintext) ->
ok;
put_header(F, Room, Date, CSSFile, Lang, Hour_offset, Date_prev, Date_next, Top_link, FileFormat) ->
fw(F, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"), fw(F, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"),
fw(F, "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"~s\" lang=\"~s\">", [Lang, Lang]), fw(F, "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"~s\" lang=\"~s\">", [Lang, Lang]),
fw(F, "<head>"), fw(F, "<head>"),
@ -618,8 +660,8 @@ put_header(F, Room, Date, CSSFile, Lang, Hour_offset, Date_prev, Date_next, Top_
{"", ""} -> ok; {"", ""} -> ok;
{SuA, Su} -> fw(F, "<div class=\"roomsubject\">~s~s~s</div>", [SuA, ?T(" has set the subject to: "), Su]) {SuA, Su} -> fw(F, "<div class=\"roomsubject\">~s~s~s</div>", [SuA, ?T(" has set the subject to: "), Su])
end, end,
RoomConfig = roomconfig_to_string(Room#room.config, Lang), RoomConfig = roomconfig_to_string(Room#room.config, Lang, FileFormat),
put_room_config(F, RoomConfig, Lang), put_room_config(F, RoomConfig, Lang, FileFormat),
Time_offset_str = case Hour_offset<0 of Time_offset_str = case Hour_offset<0 of
true -> io_lib:format("~p", [Hour_offset]); true -> io_lib:format("~p", [Hour_offset]);
false -> io_lib:format("+~p", [Hour_offset]) false -> io_lib:format("+~p", [Hour_offset])
@ -669,7 +711,9 @@ put_header_script(F) ->
fw(F, "else {document.getElementById(e).style.display='none';}}"), fw(F, "else {document.getElementById(e).style.display='none';}}"),
fw(F, "</script>"). fw(F, "</script>").
put_room_config(F, RoomConfig, Lang) -> put_room_config(_F, _RoomConfig, _Lang, plaintext) ->
ok;
put_room_config(F, RoomConfig, Lang, _FileFormat) ->
{_, Now2, _} = now(), {_, Now2, _} = now(),
fw(F, "<div class=\"rc\">"), fw(F, "<div class=\"rc\">"),
fw(F, "<div class=\"rct\" onclick=\"sh('a~p');return false;\">~s</div>", [Now2, ?T("Room Configuration")]), fw(F, "<div class=\"rct\" onclick=\"sh('a~p');return false;\">~s</div>", [Now2, ?T("Room Configuration")]),
@ -680,11 +724,18 @@ put_room_config(F, RoomConfig, Lang) ->
%% The default behaviour is to ignore the nofollow spam prevention on links %% The default behaviour is to ignore the nofollow spam prevention on links
%% (NoFollow=false) %% (NoFollow=false)
htmlize(S1) -> htmlize(S1) ->
htmlize(S1, false). htmlize(S1, html).
htmlize(S1, plaintext) ->
S1;
htmlize(S1, FileFormat) ->
htmlize(S1, false, FileFormat).
%% The NoFollow parameter tell if the spam prevention should be applied to the link found %% The NoFollow parameter tell if the spam prevention should be applied to the link found
%% true means 'apply nofollow on links'. %% true means 'apply nofollow on links'.
htmlize(S1, NoFollow) -> htmlize(S1, _NoFollow, plaintext) ->
S1;
htmlize(S1, NoFollow, _FileFormat) ->
S2_list = string:tokens(S1, "\n"), S2_list = string:tokens(S1, "\n"),
lists:foldl( lists:foldl(
fun(Si, Res) -> fun(Si, Res) ->
@ -735,20 +786,20 @@ get_room_info(RoomJID, Opts) ->
config = Opts config = Opts
}. }.
roomconfig_to_string(Options, Lang) -> roomconfig_to_string(Options, Lang, FileFormat) ->
% Get title, if available %% Get title, if available
Title = case lists:keysearch(title, 1, Options) of Title = case lists:keysearch(title, 1, Options) of
{value, Tuple} -> [Tuple]; {value, Tuple} -> [Tuple];
false -> [] false -> []
end, end,
% Remove title from list %% Remove title from list
Os1 = lists:keydelete(title, 1, Options), Os1 = lists:keydelete(title, 1, Options),
% Order list %% Order list
Os2 = lists:sort(Os1), Os2 = lists:sort(Os1),
% Add title to ordered list %% Add title to ordered list
Options2 = Title ++ Os2, Options2 = Title ++ Os2,
lists:foldl( lists:foldl(
@ -765,7 +816,7 @@ roomconfig_to_string(Options, Lang) ->
T -> T ->
case Opt of case Opt of
password -> "<div class=\"rcoe\">" ++ OptText ++ "</div>"; password -> "<div class=\"rcoe\">" ++ OptText ++ "</div>";
title -> "<div class=\"rcot\">" ++ ?T("Room title") ++ ": \"" ++ htmlize(T) ++ "\"</div>"; title -> "<div class=\"rcot\">" ++ ?T("Room title") ++ ": \"" ++ htmlize(T, FileFormat) ++ "\"</div>";
_ -> "\"" ++ T ++ "\"" _ -> "\"" ++ T ++ "\""
end end
end, end,
@ -795,7 +846,7 @@ get_roomconfig_text(_) -> undefined.
get_proc_name(Host) -> gen_mod:get_module_proc(Host, ?PROCNAME). get_proc_name(Host) -> gen_mod:get_module_proc(Host, ?PROCNAME).
calc_hour_offset(TimeHere) -> calc_hour_offset(TimeHere) ->
TimeZero = calendar:now_to_universal_time(now()), TimeZero = calendar:now_to_universal_time(now()),
TimeHereHour = calendar:datetime_to_gregorian_seconds(TimeHere) div 3600, TimeHereHour = calendar:datetime_to_gregorian_seconds(TimeHere) div 3600,
TimeZeroHour = calendar:datetime_to_gregorian_seconds(TimeZero) div 3600, TimeZeroHour = calendar:datetime_to_gregorian_seconds(TimeZero) div 3600,
TimeHereHour - TimeZeroHour. TimeHereHour - TimeZeroHour.