-include("ejabberd.hrl").
-include("jlib.hrl").
+-include("mod_muc_room.hrl").
+
+%% Copied from mod_muc/mod_muc.erl
+-record(muc_online_room, {name_host, pid}).
-define(T(Text), translate:translate(Lang, Text)).
-define(PROCNAME, ejabberd_mod_muc_log).
-record(room, {jid, title, subject, subject_author, config}).
--record(state, {host,
+-record(logstate, {host,
out_dir,
dir_type,
dir_name,
end;
L -> L
end,
- {ok, #state{host = Host,
+ {ok, #logstate{host = Host,
out_dir = OutDir,
dir_type = DirType,
dir_name = DirName,
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call({check_access_log, ServerHost, FromJID}, _From, State) ->
- Reply = acl:match_rule(ServerHost, State#state.access, FromJID),
+ Reply = acl:match_rule(ServerHost, State#logstate.access, FromJID),
{reply, Reply, State};
handle_call(stop, _From, State) ->
{stop, normal, ok, State}.
add_message_to_log(Nick, Message, Room, Opts, State)
end;
-add_to_log2(roomconfig_change, _, Room, Opts, State) ->
+add_to_log2(roomconfig_change, _Occupants, Room, Opts, State) ->
add_message_to_log("", roomconfig_change, Room, Opts, State);
+add_to_log2(roomconfig_change_enabledlogging, Occupants, Room, Opts, State) ->
+ add_message_to_log("", {roomconfig_change, Occupants}, Room, Opts, State);
+
add_to_log2(nickchange, {OldNick, NewNick}, Room, Opts, State) ->
add_message_to_log(NewNick, {nickchange, OldNick}, Room, Opts, State);
fw(F, "</span></div></body></html>").
add_message_to_log(Nick1, Message, RoomJID, Opts, State) ->
- #state{out_dir = OutDir,
+ #logstate{out_dir = OutDir,
dir_type = DirType,
dir_name = DirName,
file_format = FileFormat,
put_room_config(F, RoomConfig, Lang, FileFormat),
io_lib:format("<font class=\"mrcm\">~s</font><br/>",
[?T("Chatroom configuration modified")]);
+ {roomconfig_change, Occupants} ->
+ RoomConfig = roomconfig_to_string(Room#room.config, Lang, FileFormat),
+ put_room_config(F, RoomConfig, Lang, FileFormat),
+ RoomOccupants = roomoccupants_to_string(Occupants, FileFormat),
+ put_room_occupants(F, RoomOccupants, Lang, FileFormat),
+ io_lib:format("<font class=\"mrcm\">~s</font><br/>",
+ [?T("Chatroom configuration modified")]);
join ->
io_lib:format("<font class=\"mj\">~s ~s</font><br/>",
[Nick, ?T("joins the room")]);
end,
RoomConfig = roomconfig_to_string(Room#room.config, Lang, FileFormat),
put_room_config(F, RoomConfig, Lang, FileFormat),
+ Occupants = get_room_occupants(Room#room.jid),
+ RoomOccupants = roomoccupants_to_string(Occupants, FileFormat),
+ put_room_occupants(F, RoomOccupants, Lang, FileFormat),
Time_offset_str = case Hour_offset<0 of
true -> io_lib:format("~p", [Hour_offset]);
false -> io_lib:format("+~p", [Hour_offset])
fw(F, "<div class=\"rcos\" id=\"a~p\" style=\"display: none;\" ><br/>~s</div>", [Now2, RoomConfig]),
fw(F, "</div>").
+put_room_occupants(_F, _RoomOccupants, _Lang, plaintext) ->
+ ok;
+put_room_occupants(F, RoomOccupants, Lang, _FileFormat) ->
+ {_, Now2, _} = now(),
+ fw(F, "<div class=\"rc\">"),
+ fw(F, "<div class=\"rct\" onclick=\"sh('o~p');return false;\">~s</div>", [Now2, ?T("Room Occupants")]),
+ fw(F, "<div class=\"rcos\" id=\"o~p\" style=\"display: none;\" ><br/>~s</div>", [Now2, RoomOccupants]),
+ fw(F, "</div>").
+
%% htmlize
%% The default behaviour is to ignore the nofollow spam prevention on links
%% (NoFollow=false)
S5 = element(2, regexp:gsub(S4, "((http|https|ftp)://|(mailto|xmpp):)[^] )\'\"}]+",
link_regexp(NoFollow))),
%% Remove 'right-to-left override' unicode character 0x202e
- element(2, regexp:gsub(S5, [226,128,174], "[RLO]")).
+ S6 = element(2, regexp:gsub(S5, " ", "\\ \\ ")),
+ S7 = element(2, regexp:gsub(S6, "\\t", "\\ \\ \\ \\ ")),
+ element(2, regexp:gsub(S7, [226,128,174], "[RLO]")).
%% Regexp link
%% Add the nofollow rel attribute when required
get_roomconfig_text(logging) -> "Enable logging";
get_roomconfig_text(_) -> undefined.
+%% Users = [{JID, Nick, Role}]
+roomoccupants_to_string(Users, _FileFormat) ->
+ Res = [role_users_to_string(RoleS, Users1)
+ || {RoleS, Users1} <- group_by_role(Users), Users1 /= []],
+ lists:flatten(["<div class=\"rcot\">", Res, "</div>"]).
+
+%% Users = [{JID, Nick, Role}]
+group_by_role(Users) ->
+ {Ms, Ps, Vs, Ns} =
+ lists:foldl(
+ fun({JID, Nick, moderator}, {Mod, Par, Vis, Non}) ->
+ {[{JID, Nick}]++Mod, Par, Vis, Non};
+ ({JID, Nick, participant}, {Mod, Par, Vis, Non}) ->
+ {Mod, [{JID, Nick}]++Par, Vis, Non};
+ ({JID, Nick, visitor}, {Mod, Par, Vis, Non}) ->
+ {Mod, Par, [{JID, Nick}]++Vis, Non};
+ ({JID, Nick, none}, {Mod, Par, Vis, Non}) ->
+ {Mod, Par, Vis, [{JID, Nick}]++Non}
+ end,
+ {[], [], [], []},
+ Users),
+ case Ms of [] -> []; _ -> [{"Moderator", Ms}] end
+ ++ case Ms of [] -> []; _ -> [{"Participant", Ps}] end
+ ++ case Ms of [] -> []; _ -> [{"Visitor", Vs}] end
+ ++ case Ms of [] -> []; _ -> [{"None", Ns}] end.
+
+%% Role = atom()
+%% Users = [{JID, Nick}]
+role_users_to_string(RoleS, Users) ->
+ SortedUsers = lists:keysort(2, Users),
+ UsersString = [[Nick, "<br/>"] || {_JID, Nick} <- SortedUsers],
+ [RoleS, ": ", UsersString].
+
+get_room_occupants(RoomJIDString) ->
+ RoomJID = jlib:string_to_jid(RoomJIDString),
+ RoomName = RoomJID#jid.luser,
+ MucService = RoomJID#jid.lserver,
+ StateData = get_room_state(RoomName, MucService),
+ [{U#user.jid, U#user.nick, U#user.role}
+ || {_, U} <- ?DICT:to_list(StateData#state.users)].
+
+get_room_state(RoomName, MucService) ->
+ case mnesia:dirty_read(muc_online_room, {RoomName, MucService}) of
+ [R] ->
+ RoomPid = R#muc_online_room.pid,
+ get_room_state(RoomPid);
+ [] ->
+ room_not_found
+ end.
+
+get_room_state(RoomPid) ->
+ {ok, R} = gen_fsm:sync_send_all_state_event(RoomPid, get_state),
+ R.
+
get_proc_name(Host) -> gen_mod:get_module_proc(Host, ?PROCNAME).
calc_hour_offset(TimeHere) ->