]> granicus.if.org Git - ejabberd/commitdiff
* src/mod_muc/mod_muc_log.erl: MUC log files options: plaintext
authorBadlop <badlop@process-one.net>
Mon, 18 Aug 2008 19:08:30 +0000 (19:08 +0000)
committerBadlop <badlop@process-one.net>
Mon, 18 Aug 2008 19:08:30 +0000 (19:08 +0000)
format; filename with only room name (EJAB-596)
* doc/guide.tex: Document both options
* doc/guide.html: Likewise

SVN Revision: 1531

ChangeLog
doc/guide.html
doc/guide.tex
src/mod_muc/mod_muc_log.erl

index 5132512e8a9be61e1d65265024bbed0e57eb6c38..a666b3cc0341322ba7d5d6bbc01186e1f84fbc68 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 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
        returns success regardless of real result (EJAB-723)
        * src/ejabberd_auth.erl: Likewise
index b944bdff0a746da086211fc36a9e566d9bd15fa4..f916476a0263229ddd751b2f4938f9c632c4341a 100644 (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
 custom CSS file (for example: &#X2018;http://example.com/my.css&#X2019;). The default value
 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">
 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,
 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.
 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">
 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
 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">
 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
 is <TT>true</TT>, which mean that nofollow attributes will be added to user
 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">
 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
@@ -2225,6 +2237,7 @@ time zone will be GMT/UTC. Finally, the top link will be
                  {access_log, muc},
                  {cssfile, "http://example.com/my.css"},
                  {dirtype, plain},
+                 {dirname, room_jid},
                  {outdir, "/var/www/muclogs"},
                  {timezone, universal},
                  {spam_prevention, true},
index d2bb0603a55b438c11a8ded7eb52a1438387989c..28488c403225e04fb788596a334e33527cfd7cea 100644 (file)
@@ -2828,26 +2828,38 @@ Options:
   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
   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}
   The type of the created directories can be specified with this option. Allowed
   values are \term{subdirs} and \term{plain}. With the first value,
   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.
   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}
   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
   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}
   To prevent spam, the \term{spam\_prevention} option adds a special attribute
   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
   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}
   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
@@ -2872,6 +2884,7 @@ Examples:
                  {access_log, muc},
                  {cssfile, "http://example.com/my.css"},
                  {dirtype, plain},
+                 {dirname, room_jid},
                  {outdir, "/var/www/muclogs"},
                  {timezone, universal},
                  {spam_prevention, true},
index 767fc7f6c0d020ee9cb65bab5ad069a986b629a5..e76904193551cc367bf8d541ef7e600588ce75cc 100644 (file)
@@ -52,6 +52,8 @@
 -record(state, {host,
                out_dir,
                dir_type,
+               dir_name,
+               file_format,
                css_file,
                access,
                lang,
@@ -113,6 +115,8 @@ check_access_log(Host, From) ->
 init([Host, Opts]) ->
     OutDir = gen_mod:get_opt(outdir, Opts, "www/muc"),
     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),
     AccessLog = gen_mod:get_opt(access_log, Opts, muc_admin),
     Timezone = gen_mod:get_opt(timezone, Opts, local),
@@ -129,6 +133,8 @@ init([Host, Opts]) ->
     {ok, #state{host = Host,
                out_dir = OutDir,
                dir_type = DirType,
+               dir_name = DirName,
+               file_format = FileFormat,
                css_file = CSSFile,
                access = AccessLog,
                lang = Lang,
@@ -231,10 +237,10 @@ add_to_log2(kickban, {Nick, Reason, Code}, Room, Opts, State) ->
 %%----------------------------------------------------------------------
 %% Core
 
-build_filename_string(TimeStamp, OutDir, RoomJID, DirType) ->
+build_filename_string(TimeStamp, OutDir, RoomJID, DirType, DirName, FileFormat) ->
     {{Year, Month, Day}, _Time} = TimeStamp,
 
-    % Directory and file names
+    %% Directory and file names
     {Dir, Filename, Rel} =
        case DirType of
            subdirs ->
@@ -248,55 +254,75 @@ build_filename_string(TimeStamp, OutDir, RoomJID, DirType) ->
                                       [Year, Month, Day])),
                {"", Date, "."}
        end,
-    Fd = filename:join([OutDir, RoomJID, Dir]),
-    Fn = filename:join([Fd, Filename ++ ".html"]),
-    Fnrel = filename:join([Rel, Dir, Filename ++ ".html"]),
+
+    RoomString = case DirName of
+                    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}.
 
-% calculate day before
+get_room_name(RoomJID) ->
+    JID = jlib:string_to_jid(RoomJID),
+    JID#jid.user.
+
+%% calculate day before
 get_timestamp_daydiff(TimeStamp, Daydiff) ->
     {Date1, HMS} = TimeStamp,
     Date2 = calendar:gregorian_days_to_date(
              calendar:date_to_gregorian_days(Date1) + Daydiff),
     {Date2, HMS}.
 
-% Try to close the previous day log, if it exists
-close_previous_log(Fn, Images_dir) ->
+%% Try to close the previous day log, if it exists
+close_previous_log(Fn, Images_dir, FileFormat) ->
     case file:read_file_info(Fn) of
        {ok, _} ->
            {ok, F} = file:open(Fn, [append]),
-           %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>"),
+           write_last_lines(F, Images_dir, FileFormat),
            file:close(F);
        _ -> ok
     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) ->
-    Nick = htmlize(Nick1),
     #state{out_dir = OutDir,
           dir_type = DirType,
+          dir_name = DirName,
+          file_format = FileFormat,
           css_file = CSSFile,
           lang = Lang,
           timezone = Timezone,
           spam_prevention = NoFollow,
           top_link = TopLink} = State,
     Room = get_room_info(RoomJID, Opts),
-
+    Nick = htmlize(Nick1, FileFormat),
+    Nick2 = htmlize("<"++Nick1++">", FileFormat),
     Now = now(),
     TimeStamp = case Timezone of
                    local -> calendar:now_to_local_time(Now);
                    universal -> calendar:now_to_universal_time(Now)
                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,
 
-    % 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
        {ok, _} ->
            {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),
            {_FdYesterday, FnYesterday, DatePrev} =
                build_filename_string(
-                 TimeStampYesterday, OutDir, Room#room.jid, DirType),
+                 TimeStampYesterday, OutDir, Room#room.jid, DirType, DirName, FileFormat),
 
            TimeStampTomorrow = get_timestamp_daydiff(TimeStamp, 1),
            {_FdTomorrow, _FnTomorrow, DateNext} =
                build_filename_string(
-                 TimeStampTomorrow, OutDir, Room#room.jid, DirType),
+                 TimeStampTomorrow, OutDir, Room#room.jid, DirType, DirName, FileFormat),
 
            HourOffset = calc_hour_offset(TimeStamp),
            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),
-               create_image_files(Images_dir),
-               Images_url = case DirType of
-                       subdirs -> "../../../images";
-                       plain -> "../images"
-               end,
-           close_previous_log(FnYesterday, Images_url)
+           create_image_files(Images_dir),
+           Images_url = case DirType of
+                            subdirs -> "../../../images";
+                            plain -> "../images"
+                        end,
+           close_previous_log(FnYesterday, Images_url, FileFormat)
     end,
 
-    % Build message
+    %% Build message
     Text = case Message of
               roomconfig_change ->
-                  RoomConfig = roomconfig_to_string(Room#room.config, Lang),
-                  put_room_config(F, RoomConfig, Lang),
+                  RoomConfig = roomconfig_to_string(Room#room.config, Lang, FileFormat),
+                  put_room_config(F, RoomConfig, Lang, FileFormat),
                   io_lib:format("<font class=\"mrcm\">~s</font><br/>", 
                                 [?T("Chatroom configuration modified")]);
               join ->  
@@ -344,19 +370,19 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) ->
                                 [Nick, ?T("leaves the room")]);
               {leave, Reason} ->  
                   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", ""} ->  
                   io_lib:format("<font class=\"mb\">~s ~s</font><br/>", 
                                 [Nick, ?T("has been banned")]);
               {kickban, "301", Reason} ->  
                   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", ""} ->  
                   io_lib:format("<font class=\"mk\">~s ~s</font><br/>", 
                                 [Nick, ?T("has been kicked")]);
               {kickban, "307", Reason} ->  
                   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", ""} ->  
                   io_lib:format("<font class=\"mk\">~s ~s</font><br/>", 
                                 [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")]);
               {nickchange, OldNick} ->  
                   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} ->  
                   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} ->  
                   case regexp:first_match(T, "^/me\s") of
                       {match, _, _} ->
                           io_lib:format("<font class=\"mne\">~s ~s</font><br/>", 
-                                        [Nick, string:substr(htmlize(T), 5)]);
+                                        [Nick, string:substr(htmlize(T,FileFormat), 5)]);
                       nomatch ->
-                          io_lib:format("<font class=\"mn\">&lt;~s&gt;</font> ~s<br/>", 
-                                        [Nick, htmlize(T,NoFollow)])
+                          io_lib:format("<font class=\"mn\">~s</font> ~s<br/>",
+                                        [Nick2, htmlize(T,NoFollow,FileFormat)])
                   end
           end,
     {Hour, Minute, Second} = Time,
@@ -388,11 +414,11 @@ add_message_to_log(Nick1, Message, RoomJID, Opts, State) ->
     {_, _, Microsecs} = Now,
     STimeUnique = io_lib:format("~s.~w", [STime, Microsecs]),
 
-    % Write message
-    file:write(F, io_lib:format("<a id=\"~s\" name=\"~s\" href=\"#~s\" class=\"ts\">[~s]</a> ~s~n",
-                               [STimeUnique, STimeUnique, STimeUnique, STime, Text])),
+    %% Write message
+    fw(F, io_lib:format("<a id=\"~s\" name=\"~s\" href=\"#~s\" class=\"ts\">[~s]</a> ", 
+                       [STimeUnique, STimeUnique, STimeUnique, STime]) ++ Text, FileFormat),
 
-    % Close file
+    %% Close file
     file:close(F),
     ok.
 
@@ -443,13 +469,13 @@ make_dir_rec(Dir) ->
     end.
 
 
-% {ok, F1}=file:open("valid-xhtml10.png", [read]).
-% {ok, F1b}=file:read(F1, 1000000).
-% c("../../ejabberd/src/jlib.erl").
-% jlib:encode_base64(F1b).
+%% {ok, F1}=file:open("valid-xhtml10.png", [read]).
+%% {ok, F1b}=file:read(F1, 1000000).
+%% c("../../ejabberd/src/jlib.erl").
+%% jlib:encode_base64(F1b).
 
 image_base64("powered-by-erlang.png") ->
-       "iVBORw0KGgoAAAANSUhEUgAAAGUAAAAfCAYAAAD+xQNoAAADN0lEQVRo3u1a"
+    "iVBORw0KGgoAAAANSUhEUgAAAGUAAAAfCAYAAAD+xQNoAAADN0lEQVRo3u1a"
        "P0waURz+rjGRRQ+nUyRCYmJyDPTapDARaSIbTUjt1gVSh8ZW69aBAR0cWLSx"
        "CXWp59LR1jbdqKnGxoQuRZZrSYyHEVM6iZMbHewROA7u3fHvkr5vOn737vcu"
        "33ffu9/vcQz+gef5Cij6CkmSGABgFEH29r5SVvqIsTEOHo8HkiQxDBXEOjg9"
@@ -471,7 +497,7 @@ image_base64("powered-by-erlang.png") ->
        "KF/d/wX3cJvREzl1vAAAAABJRU5ErkJggg==";
 
 image_base64("valid-xhtml10.png") ->
-       "iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAAEjEcpEAAACiFBMVEUAAADe"
+    "iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAAEjEcpEAAACiFBMVEUAAADe"
        "5+fOezmtra3ejEKlhELvvWO9WlrehELOe3vepaWclHvetVLGc3PerVKcCAj3"
        "vVqUjHOUe1JjlL0xOUpjjL2UAAC91ueMrc7vrVKlvdbW3u+EpcbO3ufO1ucY"
        "WpSMKQi9SiF7e3taWkoQEAiMczkQSoxaUkpzc3O1lEoICACEazEhGAgIAACE"
@@ -527,7 +553,7 @@ image_base64("valid-xhtml10.png") ->
        "QZ+RYfpNE/4Xosmq7jsZAJsAAAAASUVORK5CYII=";
 
 image_base64("vcss.png") ->
-       "iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAABUFvrSAAABKVBMVEUAAAAj"
+    "iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAABUFvrSAAABKVBMVEUAAAAj"
        "Ix8MR51ZVUqAdlmdnZ3ejEWLDAuNjY1kiMG0n2d9fX19Ghfrp1FtbW3y39+3"
        "Ph6lIRNdXV2qJBFcVUhcVUhPT0/dsmpUfLr57+/u7u4/PDWZAACZAADOp1Gd"
        "GxG+SyTgvnNdSySzk16+mkuxw+BOS0BOS0DOzs7MzMy4T09RRDwsJBG+vr73"
@@ -555,7 +581,7 @@ image_base64("vcss.png") ->
        "AElFTkSuQmCC";
 
 image_base64("powered-by-ejabberd.png") ->
-       "iVBORw0KGgoAAAANSUhEUgAAAGUAAAAfCAMAAADJG/NaAAAAw1BMVEUAAAAj"
+    "iVBORw0KGgoAAAANSUhEUgAAAGUAAAAfCAMAAADJG/NaAAAAw1BMVEUAAAAj"
        "BgYtBAM5AwFCAAAYGAJNAABcAABIDQ5qAAAoJRV7AACFAAAoKSdJHByLAAAw"
        "Lwk1NQA1MzFJKyo4NxtDQQBEQT5KSCxSTgBSUBlgQ0JYSEpZWQJPUU5hYABb"
        "W0ZiYClcW1poaCVwbQRpaDhzYWNsakhuZ2VrbFZ8dwCEgAB3dnd4d2+OjACD"
@@ -579,27 +605,43 @@ image_base64("powered-by-ejabberd.png") ->
        "AElFTkSuQmCC".
 
 create_image_files(Images_dir) ->
-       Filenames = [
-           "powered-by-ejabberd.png",
-           "powered-by-erlang.png",
-           "valid-xhtml10.png",
-           "vcss.png"
-       ],
-       lists:foreach(
-               fun(Filename) ->
-                       Filename_full = filename:join([Images_dir, Filename]),
-                       {ok, F} = file:open(Filename_full, [write]),
-                       Image = jlib:decode_base64(image_base64(Filename)),
-                       io:format(F, "~s", [Image]),
-                       file:close(F)
-               end,
-               Filenames),
-       ok.
-
-fw(F, S, O) -> io:format(F, S ++ "~n", O).
-fw(F, S) -> fw(F, S, []).
+    Filenames = ["powered-by-ejabberd.png",
+                "powered-by-erlang.png",
+                "valid-xhtml10.png",
+                "vcss.png"
+               ],
+    lists:foreach(
+      fun(Filename) ->
+             Filename_full = filename:join([Images_dir, Filename]),
+             {ok, F} = file:open(Filename_full, [write]),
+             Image = jlib:decode_base64(image_base64(Filename)),
+             io:format(F, "~s", [Image]),
+             file:close(F)
+      end,
+      Filenames),
+    ok.
 
-put_header(F, Room, Date, CSSFile, Lang, Hour_offset, Date_prev, Date_next, Top_link) ->
+fw(F, S) -> fw(F, S, [], html).
+
+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, "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"~s\" lang=\"~s\">", [Lang, Lang]),
     fw(F, "<head>"),
@@ -618,8 +660,8 @@ put_header(F, Room, Date, CSSFile, Lang, Hour_offset, Date_prev, Date_next, Top_
        {"", ""} -> ok;
        {SuA, Su} -> fw(F, "<div class=\"roomsubject\">~s~s~s</div>", [SuA, ?T(" has set the subject to: "), Su])
     end,
-    RoomConfig = roomconfig_to_string(Room#room.config, Lang),
-    put_room_config(F, RoomConfig, Lang),
+    RoomConfig = roomconfig_to_string(Room#room.config, Lang, FileFormat),
+    put_room_config(F, RoomConfig, Lang, FileFormat),
     Time_offset_str = case Hour_offset<0 of
                          true -> 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, "</script>").
 
-put_room_config(F, RoomConfig, Lang) ->
+put_room_config(_F, _RoomConfig, _Lang, plaintext) ->
+    ok;
+put_room_config(F, RoomConfig, Lang, _FileFormat) ->
     {_, Now2, _} = now(),
     fw(F, "<div class=\"rc\">"),
     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
 %% (NoFollow=false)
 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
 %% true means 'apply nofollow on links'.
-htmlize(S1, NoFollow) ->
+htmlize(S1, _NoFollow, plaintext) ->
+    S1;
+htmlize(S1, NoFollow, _FileFormat) ->
     S2_list = string:tokens(S1, "\n"),
     lists:foldl(
       fun(Si, Res) -> 
@@ -735,20 +786,20 @@ get_room_info(RoomJID, Opts) ->
          config = Opts
         }.
 
-roomconfig_to_string(Options, Lang) ->
-    % Get title, if available
+roomconfig_to_string(Options, Lang, FileFormat) ->
+    %% Get title, if available
     Title = case lists:keysearch(title, 1, Options) of
                {value, Tuple} -> [Tuple];
                false -> []
            end,
-       
-    % Remove title from list
+
+    %% Remove title from list
     Os1 = lists:keydelete(title, 1, Options),
-       
-    % Order list
+
+    %% Order list
     Os2 = lists:sort(Os1),
-       
-    % Add title to ordered list
+
+    %% Add title to ordered list
     Options2 = Title ++ Os2,
 
     lists:foldl(
@@ -765,7 +816,7 @@ roomconfig_to_string(Options, Lang) ->
                               T -> 
                                   case Opt of
                                       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 ++ "\""
                                   end
                           end,
@@ -795,7 +846,7 @@ get_roomconfig_text(_) -> undefined.
 get_proc_name(Host) -> gen_mod:get_module_proc(Host, ?PROCNAME).
 
 calc_hour_offset(TimeHere) ->
-       TimeZero = calendar:now_to_universal_time(now()),
-       TimeHereHour = calendar:datetime_to_gregorian_seconds(TimeHere) div 3600,
-       TimeZeroHour = calendar:datetime_to_gregorian_seconds(TimeZero) div 3600,
-       TimeHereHour - TimeZeroHour.
+    TimeZero = calendar:now_to_universal_time(now()),
+    TimeHereHour = calendar:datetime_to_gregorian_seconds(TimeHere) div 3600,
+    TimeZeroHour = calendar:datetime_to_gregorian_seconds(TimeZero) div 3600,
+    TimeHereHour - TimeZeroHour.