From b194fd5c99a79c55fae3f992e01fb05658c5a7cf Mon Sep 17 00:00:00 2001 From: Sonny Scroggin Date: Tue, 18 Mar 2014 11:23:25 -0500 Subject: [PATCH 01/13] Just return the value if it exists, otherwise return the default. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The guard here caused the ‘EXIT’ clause to be triggered in `ejabberd_config:prepare_opt_val/4` on line 573 of `ejabberd_config.erl`. --- mod_rest/src/mod_rest.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod_rest/src/mod_rest.erl b/mod_rest/src/mod_rest.erl index fab4a59..efbb982 100644 --- a/mod_rest/src/mod_rest.erl +++ b/mod_rest/src/mod_rest.erl @@ -111,7 +111,7 @@ try_get_option(Host, OptionName, DefaultValue) -> true -> ok; _ -> throw({module_must_be_started_in_vhost, ?MODULE, Host}) end, - gen_mod:get_module_opt(Host, ?MODULE, OptionName, fun(I) when I -> I end, DefaultValue). + gen_mod:get_module_opt(Host, ?MODULE, OptionName, fun(I) -> I end, DefaultValue). get_option_access(Host) -> try_get_option(Host, access_commands, []). From 9a30d2d0224bae25c811295c09958fd98808164e Mon Sep 17 00:00:00 2001 From: Sonny Scroggin Date: Tue, 18 Mar 2014 11:23:54 -0500 Subject: [PATCH 02/13] Clean up. --- mod_rest/src/mod_rest.erl | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/mod_rest/src/mod_rest.erl b/mod_rest/src/mod_rest.erl index efbb982..24074b2 100644 --- a/mod_rest/src/mod_rest.erl +++ b/mod_rest/src/mod_rest.erl @@ -46,11 +46,7 @@ start(_Host, _Opts) -> stop(_Host) -> ok. -process([], #request{method = 'POST', - data = Data, - host = Host, - ip = ClientIp - }) -> +process([], #request{method = 'POST', data = Data, host = Host, ip = ClientIp}) -> try {ClientAddress, _PortNumber} = ClientIp, check_member_option(Host, ClientAddress, allowed_ips), From 73e6b7ed227fd477aa8ca15cff6fdd21375b861a Mon Sep 17 00:00:00 2001 From: Sonny Scroggin Date: Tue, 18 Mar 2014 11:34:21 -0500 Subject: [PATCH 03/13] Add support for using yaml config file. When converting to use the yaml config, the option for `allowed_ips` gets stored as a binary. But needs to be compared against the client ip of the request (which is a tuple). This converts the list of binaries into a list of ip tuples. --- mod_rest/src/mod_rest.erl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/mod_rest/src/mod_rest.erl b/mod_rest/src/mod_rest.erl index 24074b2..152ee0b 100644 --- a/mod_rest/src/mod_rest.erl +++ b/mod_rest/src/mod_rest.erl @@ -119,12 +119,31 @@ check_stanza(Stanza, _From, To, Host) -> check_member_option(Host, StanzaType, allowed_stanza_types), allowed. +check_member_option(Host, ClientIp, allowed_ips) -> + true = case try_get_option(Host, allowed_ips, all) of + all -> true; + AllowedValues -> + case lists:all(fun(El) -> is_binary(El) end, AllowedValues) of + true -> + AllowedIps = lists:map(fun(El) -> + binary_to_ip_tuple(El) + end, + AllowedValues), + lists:member(ClientIp, AllowedIps); + false -> + lists:member(ClientIp, AllowedValues) + end + end; check_member_option(Host, Element, Option) -> true = case try_get_option(Host, Option, all) of all -> true; AllowedValues -> lists:member(Element, AllowedValues) end. +binary_to_ip_tuple(IpAddress) when is_binary(IpAddress) -> + {ok, IpTuple} = inet_parse:address(binary_to_list(IpAddress)), + IpTuple. + post_request(Stanza, From, To) -> case ejabberd_router:route(From, To, Stanza) of ok -> {200, [], <<"Ok">>}; From 911eb5b1998959c811a758a99aba9a733ec3b41d Mon Sep 17 00:00:00 2001 From: Badlop Date: Mon, 24 Mar 2014 19:01:43 +0100 Subject: [PATCH 04/13] Update get_vcard and set_vcard to ejabberd 13 (fixes issue #21) --- mod_admin_extra/src/mod_admin_extra.erl | 30 ++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/mod_admin_extra/src/mod_admin_extra.erl b/mod_admin_extra/src/mod_admin_extra.erl index 2591769..dcc41d8 100644 --- a/mod_admin_extra/src/mod_admin_extra.erl +++ b/mod_admin_extra/src/mod_admin_extra.erl @@ -320,38 +320,38 @@ commands() -> desc = "Get content from a vCard field", longdesc = Vcard1FieldsString ++ "\n" ++ Vcard2FieldsString ++ "\n\n" ++ VcardXEP, module = ?MODULE, function = get_vcard, - args = [{user, string}, {host, string}, {name, string}], + args = [{user, binary}, {host, binary}, {name, binary}], result = {content, string}}, #ejabberd_commands{name = get_vcard2, tags = [vcard], desc = "Get content from a vCard field", longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n" ++ VcardXEP, module = ?MODULE, function = get_vcard, - args = [{user, string}, {host, string}, {name, string}, {subname, string}], + args = [{user, binary}, {host, binary}, {name, binary}, {subname, binary}], result = {content, string}}, #ejabberd_commands{name = get_vcard2_multi, tags = [vcard], desc = "Get multiple contents from a vCard field (requires exmpp installed)", longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n" ++ VcardXEP, module = ?MODULE, function = get_vcard_multi, - args = [{user, string}, {host, string}, {name, string}, {subname, string}], + args = [{user, binary}, {host, binary}, {name, binary}, {subname, binary}], result = {contents, {list, string}}}, #ejabberd_commands{name = set_vcard, tags = [vcard], desc = "Set content in a vCard field", longdesc = Vcard1FieldsString ++ "\n" ++ Vcard2FieldsString ++ "\n\n" ++ VcardXEP, module = ?MODULE, function = set_vcard, - args = [{user, string}, {host, string}, {name, string}, {content, string}], + args = [{user, binary}, {host, binary}, {name, binary}, {content, binary}], result = {res, rescode}}, #ejabberd_commands{name = set_vcard2, tags = [vcard], desc = "Set content in a vCard subfield", longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n" ++ VcardXEP, module = ?MODULE, function = set_vcard, - args = [{user, string}, {host, string}, {name, string}, {subname, string}, {content, string}], + args = [{user, binary}, {host, binary}, {name, binary}, {subname, binary}, {content, binary}], result = {res, rescode}}, #ejabberd_commands{name = set_vcard2_multi, tags = [vcard], desc = "Set multiple contents in a vCard subfield", longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n" ++ VcardXEP, module = ?MODULE, function = set_vcard, - args = [{user, string}, {host, string}, {name, string}, {subname, string}, {contents, {list, string}}], + args = [{user, binary}, {host, binary}, {name, binary}, {subname, binary}, {contents, {list, binary}}], result = {res, rescode}}, #ejabberd_commands{name = add_rosteritem, tags = [roster], @@ -966,8 +966,8 @@ set_vcard(User, Host, Name, Subname, SomeContent) -> %% Internal vcard get_module_resource(Server) -> - case gen_mod:get_module_opt(Server, ?MODULE, module_resource, none) of - none -> atom_to_list(?MODULE); + case gen_mod:get_module_opt(Server, ?MODULE, module_resource, fun(A) -> A end, none) of + none -> list_to_binary(atom_to_list(?MODULE)); R when is_list(R) -> R end. @@ -1013,8 +1013,8 @@ get_subtag_exmpp(Xmlelement, Name) -> set_vcard_content(User, Server, Data, SomeContent) -> ContentList = case SomeContent of - [Char | _] when not is_list(Char) -> [SomeContent]; - [Char | _] when is_list(Char) -> SomeContent + [Bin | _] when is_binary(Bin) -> SomeContent; + Bin when is_binary(Bin) -> [SomeContent] end, [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}), JID = jlib:make_jid(User, Server, get_module_resource(Server)), @@ -1031,7 +1031,7 @@ set_vcard_content(User, Server, Data, SomeContent) -> end, %% Build new vcard - SubEl = {xmlelement, "vCard", [{"xmlns","vcard-temp"}], A4}, + SubEl = {xmlel, <<"vCard">>, [{<<"xmlns">>,<<"vcard-temp">>}], A4}, IQ2 = #iq{type=set, sub_el = SubEl}, Module:Function(JID, JID, IQ2), @@ -1042,18 +1042,18 @@ update_vcard_els(Data, ContentList, Els1) -> [Data1 | Data2] = Data, NewEls = case Data2 of [] -> - [{xmlelement, Data1, [], [{xmlcdata,Content}]} || Content <- ContentList]; + [{xmlel, Data1, [], [{xmlcdata,Content}]} || Content <- ContentList]; [D2] -> OldEl = case lists:keysearch(Data1, 2, Els2) of {value, A} -> A; false -> {xmlelement, Data1, [], []} end, - {xmlelement, _, _, ContentOld1} = OldEl, - Content2 = [{xmlelement, D2, [], [{xmlcdata,Content}]} || Content <- ContentList], + {xmlel, _, _, ContentOld1} = OldEl, + Content2 = [{xmlel, D2, [], [{xmlcdata,Content}]} || Content <- ContentList], ContentOld2 = [A || {_, X, _, _} = A <- ContentOld1, X/=D2], ContentOld3 = lists:keysort(2, ContentOld2), ContentNew = lists:keymerge(2, Content2, ContentOld3), - [{xmlelement, Data1, [], ContentNew}] + [{xmlel, Data1, [], ContentNew}] end, Els3 = lists:keydelete(Data1, 2, Els2), lists:keymerge(2, NewEls, Els3). From 73c553be75f09a6b8fb9a4b39cec53776a51299e Mon Sep 17 00:00:00 2001 From: Sonny Scroggin Date: Tue, 25 Mar 2014 11:15:53 -0500 Subject: [PATCH 05/13] Fix add_rosteritem, delete_rosteritem, and get_roster --- mod_admin_extra/src/mod_admin_extra.erl | 39 ++++++++++++------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/mod_admin_extra/src/mod_admin_extra.erl b/mod_admin_extra/src/mod_admin_extra.erl index dcc41d8..5208c9f 100644 --- a/mod_admin_extra/src/mod_admin_extra.erl +++ b/mod_admin_extra/src/mod_admin_extra.erl @@ -357,9 +357,9 @@ commands() -> #ejabberd_commands{name = add_rosteritem, tags = [roster], desc = "Add an item to a user's roster (supports ODBC)", module = ?MODULE, function = add_rosteritem, - args = [{localuser, string}, {localserver, string}, - {user, string}, {server, string}, - {nick, string}, {group, string}, + args = [{localuser, binary}, {localserver, binary}, + {user, binary}, {server, binary}, + {nick, binary}, {group, binary}, {subs, string}], result = {res, rescode}}, %%{"", "subs= none, from, to or both"}, @@ -368,8 +368,8 @@ commands() -> #ejabberd_commands{name = delete_rosteritem, tags = [roster], desc = "Delete an item from a user's roster (supports ODBC)", module = ?MODULE, function = delete_rosteritem, - args = [{localuser, string}, {localserver, string}, - {user, string}, {server, string}], + args = [{localuser, binary}, {localserver, binary}, + {user, binary}, {server, binary}], result = {res, rescode}}, #ejabberd_commands{name = process_rosteritems, tags = [roster], desc = "List or delete rosteritems that match filtering options", @@ -413,7 +413,7 @@ commands() -> #ejabberd_commands{name = get_roster, tags = [roster], desc = "Get roster of a local user", module = ?MODULE, function = get_roster, - args = [{user, string}, {host, string}], + args = [{user, binary}, {host, binary}], result = {contacts, {list, {contact, {tuple, [ {jid, string}, {nick, string}, @@ -1084,8 +1084,8 @@ subscribe(LU, LS, User, Server, Nick, Group, Subscription, _Xattrs) -> {ok, M} = loaded_module(LS,[mod_roster_odbc,mod_roster]), M:set_items( LU, LS, - {xmlelement,"query", - [{"xmlns","jabber:iq:roster"}], + {xmlel, <<"query">>, + [{<<"xmlns">>, <<"jabber:iq:roster">>}], [ItemEl]}). delete_rosteritem(LocalUser, LocalServer, User, Server) -> @@ -1102,8 +1102,8 @@ unsubscribe(LU, LS, User, Server) -> {ok, M} = loaded_module(LS,[mod_roster_odbc,mod_roster]), M:set_items( LU, LS, - {xmlelement,"query", - [{"xmlns","jabber:iq:roster"}], + {xmlel, <<"query">>, + [{<<"xmlns">>, <<"jabber:iq:roster">>}], [ItemEl]}). loaded_module(Domain,Options) -> @@ -1136,8 +1136,7 @@ make_roster_xmlrpc(Roster) -> [] -> [""]; Gs -> Gs end, - ItemsX = [{JIDS, Nick, Subs, Ask, Group} - || Group <- Groups], + ItemsX = [{JIDS, Nick, Subs, Ask, Group} || Group <- Groups], ItemsX ++ Res end, [], @@ -1203,16 +1202,16 @@ push_roster_item(LU, LS, R, U, S, Action) -> ejabberd_router:route(LJID, LJID, ResIQ). build_roster_item(U, S, {add, Nick, Subs, Group}) -> - {xmlelement, "item", - [{"jid", jlib:jid_to_string(jlib:make_jid(U, S, ""))}, - {"name", Nick}, - {"subscription", Subs}], - [{xmlelement, "group", [], [{xmlcdata, Group}]}] + {xmlel, <<"item">>, + [{<<"jid">>, jlib:jid_to_string(jlib:make_jid(U, S, <<>>))}, + {<<"name">>, Nick}, + {<<"subscription">>, Subs}], + [{xmlel, <<"group">>, [], [{xmlcdata, Group}]}] }; build_roster_item(U, S, remove) -> - {xmlelement, "item", - [{"jid", jlib:jid_to_string(jlib:make_jid(U, S, ""))}, - {"subscription", "remove"}], + {xmlel, <<"item">>, + [{<<"jid">>, jlib:jid_to_string(jlib:make_jid(U, S, <<>>))}, + {<<"subscription">>, <<"remove">>}], [] }. From a8fba1ca304a01dfe372ff4e2b8ee209b20f7dd9 Mon Sep 17 00:00:00 2001 From: Badlop Date: Tue, 25 Mar 2014 18:17:14 +0100 Subject: [PATCH 06/13] Fix get_vcard and set_vcard when using option module_resource (issue #21) --- mod_admin_extra/src/mod_admin_extra.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod_admin_extra/src/mod_admin_extra.erl b/mod_admin_extra/src/mod_admin_extra.erl index dcc41d8..b752b24 100644 --- a/mod_admin_extra/src/mod_admin_extra.erl +++ b/mod_admin_extra/src/mod_admin_extra.erl @@ -968,7 +968,7 @@ set_vcard(User, Host, Name, Subname, SomeContent) -> get_module_resource(Server) -> case gen_mod:get_module_opt(Server, ?MODULE, module_resource, fun(A) -> A end, none) of none -> list_to_binary(atom_to_list(?MODULE)); - R when is_list(R) -> R + R when is_binary(R) -> R end. get_vcard_content(User, Server, Data) -> From f7c243ab4fc4d415043f2c79d07ac0450751ee83 Mon Sep 17 00:00:00 2001 From: Badlop Date: Wed, 2 Apr 2014 11:23:04 +0200 Subject: [PATCH 07/13] Update add_roster_item and get_roster to ejabberd 13 --- mod_admin_extra/src/mod_admin_extra.erl | 40 ++++++++----------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/mod_admin_extra/src/mod_admin_extra.erl b/mod_admin_extra/src/mod_admin_extra.erl index 0f47c6f..c3480f0 100644 --- a/mod_admin_extra/src/mod_admin_extra.erl +++ b/mod_admin_extra/src/mod_admin_extra.erl @@ -360,7 +360,7 @@ commands() -> args = [{localuser, binary}, {localserver, binary}, {user, binary}, {server, binary}, {nick, binary}, {group, binary}, - {subs, string}], + {subs, binary}], result = {res, rescode}}, %%{"", "subs= none, from, to or both"}, %%{"", "example: add-roster peter localhost mike server.com MiKe Employees both"}, @@ -1064,7 +1064,7 @@ update_vcard_els(Data, ContentList, Els1) -> %%% add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs) -> - case add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, list_to_atom(Subs), []) of + case add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs, []) of {atomic, ok} -> push_roster_item(LocalUser, LocalServer, User, Server, {add, Nick, Subs, Group}), ok; @@ -1076,13 +1076,8 @@ add_rosteritem(LU, LS, User, Server, Nick, Group, Subscription, Xattrs) -> subscribe(LU, LS, User, Server, Nick, Group, Subscription, Xattrs). subscribe(LU, LS, User, Server, Nick, Group, Subscription, _Xattrs) -> - SubscriptionS = case is_atom(Subscription) of - true -> atom_to_list(Subscription); - false -> Subscription - end, - ItemEl = build_roster_item(User, Server, {add, Nick, SubscriptionS, Group}), - {ok, M} = loaded_module(LS,[mod_roster_odbc,mod_roster]), - M:set_items( + ItemEl = build_roster_item(User, Server, {add, Nick, Subscription, Group}), + mod_roster:set_items( LU, LS, {xmlel, <<"query">>, [{<<"xmlns">>, <<"jabber:iq:roster">>}], @@ -1099,22 +1094,12 @@ delete_rosteritem(LocalUser, LocalServer, User, Server) -> unsubscribe(LU, LS, User, Server) -> ItemEl = build_roster_item(User, Server, remove), - {ok, M} = loaded_module(LS,[mod_roster_odbc,mod_roster]), - M:set_items( + mod_roster:set_items( LU, LS, {xmlel, <<"query">>, [{<<"xmlns">>, <<"jabber:iq:roster">>}], [ItemEl]}). -loaded_module(Domain,Options) -> - LoadedModules = gen_mod:loaded_modules(Domain), - case lists:filter(fun(Module) -> - lists:member(Module, LoadedModules) - end, Options) of - [M|_] -> {ok, M}; - [] -> {error,not_found} - end. - %% ----------------------------- %% Get Roster %% ----------------------------- @@ -1170,7 +1155,7 @@ subscribe_roster({Name, Server, Group, Nick}, [{Name, Server, _, _} | Roster]) - subscribe_roster({Name, Server, Group, Nick}, Roster); %% Subscribe Name2 to Name1 subscribe_roster({Name1, Server1, Group1, Nick1}, [{Name2, Server2, Group2, Nick2} | Roster]) -> - subscribe(Name1, Server1, Name2, Server2, Nick2, Group2, both, []), + subscribe(Name1, Server1, Name2, Server2, Nick2, Group2, <<"both">>, []), subscribe_roster({Name1, Server1, Group1, Nick1}, Roster). push_alltoall(S, G) -> @@ -1216,24 +1201,23 @@ build_roster_item(U, S, remove) -> }. build_iq_roster_push(Item) -> - {xmlelement, "iq", - [{"type", "set"}, {"id", "push"}], - [{xmlelement, "query", - [{"xmlns", ?NS_ROSTER}], + {xmlel, <<"iq">>, + [{<<"type">>, <<"set">>}, {<<"id">>, <<"pushaaa">>}], + [{xmlel, <<"query">>, + [{<<"xmlns">>, ?NS_ROSTER}], [Item] } ] }. build_broadcast(U, S, {add, _Nick, Subs, _Group}) -> - build_broadcast(U, S, list_to_atom(Subs)); + build_broadcast(U, S, list_to_atom(binary_to_list(Subs))); build_broadcast(U, S, remove) -> build_broadcast(U, S, none); %% @spec (U::string(), S::string(), Subs::atom()) -> any() %% Subs = both | from | to | none build_broadcast(U, S, SubsAtom) when is_atom(SubsAtom) -> - {xmlelement, "broadcast", [], - [{item, {U, S, ""}, SubsAtom}] + {broadcast, {item, {U, S, <<>>}, SubsAtom} }. %%% From b77645eecc9b6e017e0b7e88944a5115373ba670 Mon Sep 17 00:00:00 2001 From: Sonny Scroggin Date: Tue, 1 Apr 2014 21:17:08 -0500 Subject: [PATCH 08/13] More binary conversions --- mod_admin_extra/src/mod_admin_extra.erl | 111 ++++++++++++------------ 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/mod_admin_extra/src/mod_admin_extra.erl b/mod_admin_extra/src/mod_admin_extra.erl index c3480f0..28918c0 100644 --- a/mod_admin_extra/src/mod_admin_extra.erl +++ b/mod_admin_extra/src/mod_admin_extra.erl @@ -219,22 +219,22 @@ commands() -> #ejabberd_commands{name = kick_session, tags = [session], desc = "Kick a user session", module = ?MODULE, function = kick_session, - args = [{user, string}, {host, string}, {resource, string}, {reason, string}], + args = [{user, binary}, {host, binary}, {resource, binary}, {reason, binary}], result = {res, rescode}}, #ejabberd_commands{name = status_num_host, tags = [session, stats], desc = "Number of logged users with this status in host", module = ?MODULE, function = status_num, - args = [{host, string}, {status, string}], + args = [{host, binary}, {status, binary}], result = {users, integer}}, #ejabberd_commands{name = status_num, tags = [session, stats], desc = "Number of logged users with this status", module = ?MODULE, function = status_num, - args = [{status, string}], + args = [{status, binary}], result = {users, integer}}, #ejabberd_commands{name = status_list_host, tags = [session], desc = "List of users logged in host with their statuses", module = ?MODULE, function = status_list, - args = [{host, string}, {status, string}], + args = [{host, binary}, {status, binary}], result = {users, {list, {userstatus, {tuple, [ {user, string}, @@ -247,7 +247,7 @@ commands() -> #ejabberd_commands{name = status_list, tags = [session], desc = "List of logged users with this status", module = ?MODULE, function = status_list, - args = [{status, string}], + args = [{status, binary}], result = {users, {list, {userstatus, {tuple, [ {user, string}, @@ -809,20 +809,20 @@ kick_session(User, Server, Resource, ReasonText) -> kick_this_session(User, Server, Resource, Reason) -> ejabberd_router:route( - jlib:make_jid("", "", ""), + jlib:make_jid(<<>>, <<>>, <<>>), jlib:make_jid(User, Server, Resource), - {xmlelement, "broadcast", [], [{exit, Reason}]}). + {xmlel, <<"broadcast">>, [], [{exit, Reason}]}). status_num(Host, Status) -> length(get_status_list(Host, Status)). status_num(Status) -> - status_num("all", Status). + status_num(<<"all">>, Status). status_list(Host, Status) -> Res = get_status_list(Host, Status), [{U, S, R, P, St} || {U, S, R, P, St} <- Res]. status_list(Status) -> - status_list("all", Status). + status_list(<<"all">>, Status). get_status_list(Host, Status_required) -> @@ -831,7 +831,7 @@ get_status_list(Host, Status_required) -> %% Reformat the list Sessions2 = [ {Session#session.usr, Session#session.sid, Session#session.priority} || Session <- Sessions], Fhost = case Host of - "all" -> + <<"all">> -> %% All hosts are requested, so dont filter at all fun(_, _) -> true end; _ -> @@ -843,7 +843,7 @@ get_status_list(Host, Status_required) -> Sessions4 = [ {ejabberd_c2s:get_presence(Pid), Server, Priority} || {Pid, Server, Priority} <- Sessions3], %% Filter by status Fstatus = case Status_required of - "all" -> + <<"all">> -> fun(_, _) -> true end; _ -> fun(A, B) -> A == B end @@ -882,18 +882,18 @@ dirty_get_sessions_list2() -> %% Make string more print-friendly stringize(String) -> %% Replace newline characters with other code - ejabberd_regexp:greplace(String, "\n", "\\n"). + ejabberd_regexp:greplace(String, <<"\n">>, <<"\\n">>). set_presence(User, Host, Resource, Type, Show, Status, Priority) -> Pid = ejabberd_sm:get_session_pid(User, Host, Resource), USR = User ++ "@" ++ Host ++ "/" ++ Resource, US = User ++ "@" ++ Host, Message = {route_xmlstreamelement, - {xmlelement, "presence", - [{"from", USR}, {"to", US}, {"type", Type}], - [{xmlelement, "show", [], [{xmlcdata, Show}]}, - {xmlelement, "status", [], [{xmlcdata, Status}]}, - {xmlelement, "priority", [], [{xmlcdata, Priority}]}]}}, + {xmlel, <<"presence">>, + [{<<"from">>, USR}, {<<"to">>, US}, {<<"type">>, Type}], + [{xmlel, <<"show">>, [], [{xmlcdata, Show}]}, + {xmlel, <<"status">>, [], [{xmlcdata, Status}]}, + {xmlel, <<"priority">>, [], [{xmlcdata, Priority}]}]}}, Pid ! Message. user_sessions_info(User, Host) -> @@ -929,14 +929,14 @@ user_sessions_info(User, Host) -> set_nickname(User, Host, Nickname) -> R = mod_vcard:process_sm_iq( - {jid, User, Host, "", User, Host, ""}, - {jid, User, Host, "", User, Host, ""}, - {iq, "", set, "", "en", - {xmlelement, "vCard", - [{"xmlns", "vcard-temp"}], [ - {xmlelement, "NICKNAME", [], [{xmlcdata, Nickname}]} - ] - }}), + {jid, User, Host, <<>>, User, Host, <<>>}, + {jid, User, Host, <<>>, User, Host, <<>>}, + {iq, <<>>, set, <<>>, <<"en">>, + {xmlel, <<"vCard">>, [ + {<<"xmlns">>, <<"vcard-temp">>}], [ + {xmlel, <<"NICKNAME">>, [], [{xmlcdata, Nickname}]} + ] + }}), case R of {iq, [], result, [], _L, []} -> ok; @@ -1046,7 +1046,7 @@ update_vcard_els(Data, ContentList, Els1) -> [D2] -> OldEl = case lists:keysearch(Data1, 2, Els2) of {value, A} -> A; - false -> {xmlelement, Data1, [], []} + false -> {xmlel, Data1, [], []} end, {xmlel, _, _, ContentOld1} = OldEl, Content2 = [{xmlel, D2, [], [{xmlcdata,Content}]} || Content <- ContentList], @@ -1118,7 +1118,7 @@ make_roster_xmlrpc(Roster) -> Subs = atom_to_list(Item#roster.subscription), Ask = atom_to_list(Item#roster.ask), Groups = case Item#roster.groups of - [] -> [""]; + [] -> [<<>>]; Gs -> Gs end, ItemsX = [{JIDS, Nick, Subs, Ask, Group} || Group <- Groups], @@ -1134,7 +1134,7 @@ make_roster_xmlrpc(Roster) -> push_roster(File, User, Server) -> {ok, [Roster]} = file:consult(File), - subscribe_roster({User, Server, "", User}, Roster). + subscribe_roster({User, Server, <<>>, User}, Roster). push_roster_all(File) -> {ok, [Roster]} = file:consult(File), @@ -1202,7 +1202,7 @@ build_roster_item(U, S, remove) -> build_iq_roster_push(Item) -> {xmlel, <<"iq">>, - [{<<"type">>, <<"set">>}, {<<"id">>, <<"pushaaa">>}], + [{<<"type">>, <<"set">>}, {<<"id">>, <<"push">>}], [{xmlel, <<"query">>, [{<<"xmlns">>, ?NS_ROSTER}], [Item] @@ -1214,11 +1214,10 @@ build_broadcast(U, S, {add, _Nick, Subs, _Group}) -> build_broadcast(U, S, list_to_atom(binary_to_list(Subs))); build_broadcast(U, S, remove) -> build_broadcast(U, S, none); -%% @spec (U::string(), S::string(), Subs::atom()) -> any() +%% @spec (U::binary(), S::binary(), Subs::atom()) -> any() %% Subs = both | from | to | none build_broadcast(U, S, SubsAtom) when is_atom(SubsAtom) -> - {broadcast, {item, {U, S, <<>>}, SubsAtom} - }. + {broadcast, {item, {U, S, <<>>}, SubsAtom}}. %%% %%% Last Activity @@ -1260,15 +1259,15 @@ set_last(User, Server, Timestamp, Status) -> %% Cluth private_get(Username, Host, Element, Ns) -> - From = jlib:make_jid(Username, Host, ""), - To = jlib:make_jid(Username, Host, ""), - IQ = {iq, "", get, ?NS_PRIVATE, "", - {xmlelement,"query", - [{"xmlns",?NS_PRIVATE}], - [{xmlelement, Element, [{"xmlns", Ns}], []}]}}, + From = jlib:make_jid(Username, Host, <<>>), + To = jlib:make_jid(Username, Host, <<>>), + IQ = {iq, <<>>, get, ?NS_PRIVATE, <<>>, + {xmlel, <<"query">>, + [{<<"xmlns">>,?NS_PRIVATE}], + [{xmlel, Element, [{<<"xmlns">>, Ns}], []}]}}, ResIq = mod_private:process_sm_iq(From, To, IQ), - [{xmlelement,"query", - [{"xmlns","jabber:iq:private"}], + [{xmlel, <<"query">>, + [{<<"xmlns">>, <<"jabber:iq:private">>}], [SubEl]}] = ResIq#iq.sub_el, xml:element_to_string(SubEl). @@ -1283,11 +1282,11 @@ private_set(Username, Host, ElementString) -> end. private_set2(Username, Host, Xml) -> - From = jlib:make_jid(Username, Host, ""), - To = jlib:make_jid(Username, Host, ""), - IQ = {iq, "", set, ?NS_PRIVATE, "", - {xmlelement,"query", - [{"xmlns",?NS_PRIVATE}], + From = jlib:make_jid(Username, Host, <<>>), + To = jlib:make_jid(Username, Host, <<>>), + IQ = {iq, <<>>, set, ?NS_PRIVATE, <<>>, + {xmlel, <<"query">>, + [{<<"xmlns">>, ?NS_PRIVATE}], [Xml]}}, mod_private:process_sm_iq(From, To, IQ), ok. @@ -1324,7 +1323,7 @@ srg_get_info(Group, Host) -> srg_get_members(Group, Host) -> Members = mod_shared_roster:get_group_explicit_users(Host,Group), - [jlib:jid_to_string(jlib:make_jid(MUser, MServer, <<"">>)) + [jlib:jid_to_string(jlib:make_jid(MUser, MServer, <<>>)) || {MUser, MServer} <- Members]. srg_user_add(User, Host, Group, GroupHost) -> @@ -1366,7 +1365,7 @@ send_packet_all_resources(FromJIDString, ToJIDString, Packet) -> ToUser = ToJID#jid.user, ToServer = ToJID#jid.server, case ToJID#jid.resource of - "" -> + <<>> -> send_packet_all_resources(FromJID, ToUser, ToServer, Packet); Res -> send_packet_all_resources(FromJID, ToUser, ToServer, Res, Packet) @@ -1375,7 +1374,7 @@ send_packet_all_resources(FromJIDString, ToJIDString, Packet) -> send_packet_all_resources(FromJID, ToUser, ToServer, Packet) -> case ejabberd_sm:get_user_resources(ToUser, ToServer) of [] -> - send_packet_all_resources(FromJID, ToUser, ToServer, "", Packet); + send_packet_all_resources(FromJID, ToUser, ToServer, <<>>, Packet); ToResources -> lists:foreach( fun(ToResource) -> @@ -1391,15 +1390,15 @@ send_packet_all_resources(FromJID, ToU, ToS, ToR, Packet) -> build_packet(message_chat, [Body]) -> - {xmlelement, "message", - [{"type", "chat"}, {"id", randoms:get_string()}], - [{xmlelement, "body", [], [{xmlcdata, Body}]}] + {xmlel, <<"message">>, + [{<<"type">>, <<"chat">>}, {<<"id">>, randoms:get_string()}], + [{xmlel, <<"body">>, [], [{xmlcdata, Body}]}] }; build_packet(message_headline, [Subject, Body]) -> - {xmlelement, "message", - [{"type", "headline"}, {"id", randoms:get_string()}], - [{xmlelement, "subject", [], [{xmlcdata, Subject}]}, - {xmlelement, "body", [], [{xmlcdata, Body}]} + {xmlel, <<"message">>, + [{<<"type">>, <<"headline">>}, {<<"id">>, randoms:get_string()}], + [{xmlel, <<"subject">>, [], [{xmlcdata, Subject}]}, + {xmlel, <<"body">>, [], [{xmlcdata, Body}]} ] }. @@ -1412,7 +1411,7 @@ privacy_set(Username, Host, QueryS) -> From = jlib:string_to_jid(Username ++ "@" ++ Host), To = jlib:string_to_jid(Host), QueryEl = xml_stream:parse_element(QueryS), - StanzaEl = {xmlelement, "iq", [{"type", "set"}], [QueryEl]}, + StanzaEl = {xmlel, <<"iq">>, [{<<"type">>, <<"set">>}], [QueryEl]}, IQ = jlib:iq_query_info(StanzaEl), ejabberd_hooks:run_fold( privacy_iq_set, From 09775d41dbb8eb15aa59e91969011cc7ecea4926 Mon Sep 17 00:00:00 2001 From: Badlop Date: Thu, 3 Apr 2014 17:45:23 +0200 Subject: [PATCH 09/13] Some updates to work a little more with ejaberd 13 binaryzation --- mod_statsdx/src/mod_statsdx.erl | 465 ++++++++++++++++---------------- 1 file changed, 237 insertions(+), 228 deletions(-) diff --git a/mod_statsdx/src/mod_statsdx.erl b/mod_statsdx/src/mod_statsdx.erl index 196c1a6..3b5422c 100644 --- a/mod_statsdx/src/mod_statsdx.erl +++ b/mod_statsdx/src/mod_statsdx.erl @@ -29,9 +29,12 @@ -include("ejabberd.hrl"). -include("ejabberd_commands.hrl"). -include("jlib.hrl"). +-include("logger.hrl"). -include("mod_roster.hrl"). --include("web/ejabberd_http.hrl"). --include("web/ejabberd_web_admin.hrl"). +-include("ejabberd_http.hrl"). +-include("ejabberd_web_admin.hrl"). + +-define(XCTB(Name, Text), ?XCT(list_to_binary(Name), list_to_binary(Text))). -define(PROCNAME, ejabberd_mod_statsdx). @@ -42,7 +45,7 @@ %%%% Module control start(Host, Opts) -> - Hooks = gen_mod:get_opt(hooks, Opts, false), + Hooks = gen_mod:get_opt(hooks, Opts, fun(O) -> is_atom(O) end, false), %% Default value for the counters CD = case Hooks of true -> 0; @@ -75,7 +78,9 @@ stop(Host) -> %%%================================== %%%% Stats Server -table_name(server) -> gen_mod:get_module_proc("server", mod_statsdx); +%%% +++ TODO: why server and "server" +table_name(server) -> gen_mod:get_module_proc(<<"server">>, mod_statsdx); +table_name("server") -> gen_mod:get_module_proc(<<"server">>, mod_statsdx); table_name(Host) -> gen_mod:get_module_proc(Host, mod_statsdx). initialize_stats_server() -> @@ -831,7 +836,7 @@ update_counter_create(Table, Element, C) -> get_tag_cdata_subtag(E, T) -> E2 = xml:get_subtag(E, T), case E2 of - false -> "unknown"; + false -> <<"unknown">>; _ -> xml:get_tag_cdata(E2) end. @@ -908,7 +913,7 @@ get_client_os(Server) -> CO1 = ets:match(table_name(Server), {{client_os, Server, '$1', '$2'}, '$3'}), CO2 = lists:map( fun([Cl, Os, A3]) -> - {lists:flatten([atom_to_list(Cl), "/", atom_to_list(Os)]), A3} + {list_to_binary(lists:flatten([atom_to_list(Cl), "/", atom_to_list(Os)])), A3} end, CO1 ), @@ -918,7 +923,7 @@ get_client_conntype(Server) -> CO1 = ets:match(table_name(Server), {{client_conntype, Server, '$1', '$2'}, '$3'}), CO2 = lists:map( fun([Cl, Os, A3]) -> - {lists:flatten([atom_to_list(Cl), "/", atom_to_list(Os)]), A3} + {list_to_binary(lists:flatten([atom_to_list(Cl), "/", atom_to_list(Os)])), A3} end, CO1 ), @@ -958,73 +963,73 @@ localtime_to_string({{Y, Mo, D},{H, Mi, S}}) -> %%%% Web Admin Menu web_menu_main(Acc, Lang) -> - Acc ++ [{"statsdx", ?T("Statistics Dx")}]. + Acc ++ [{<<"statsdx">>, ?T(<<"Statistics Dx">>)}]. web_menu_node(Acc, _Node, Lang) -> - Acc ++ [{"statsdx", ?T("Statistics Dx")}]. + Acc ++ [{<<"statsdx">>, ?T(<<"Statistics Dx">>)}]. web_menu_host(Acc, _Host, Lang) -> - Acc ++ [{"statsdx", ?T("Statistics Dx")}]. + Acc ++ [{<<"statsdx">>, ?T(<<"Statistics Dx">>)}]. %%%================================== %%%% Web Admin Page -web_page_main(_, #request{path=["statsdx"], lang = Lang} = _Request) -> - Res = [?XC("h1", ?T("Statistics")++" Dx"), - ?XC("h3", "Accounts"), - ?XAE("table", [], - [?XE("tbody", [ +web_page_main(_, #request{path=[<<"statsdx">>], lang = Lang} = _Request) -> + Res = [?XC(<<"h1">>, <<(?T(<<"Statistics">>))/binary, " Dx">>), + ?XC(<<"h3">>, <<"Accounts">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(global, Lang, "registeredusers") ]) ]), - ?XC("h3", "Roster"), - ?XAE("table", [], - [?XE("tbody", [ + ?XC(<<"h3">>, <<"Roster">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(global, Lang, "totalrosteritems"), do_stat(global, Lang, "meanitemsinroster"), - ?XE("tr", - [?XE("td", [?CT("Top rosters")]), - ?XE("td", [ - ?ACT("top/roster/30", "30"), ?C(", "), - ?ACT("top/roster/100", "100"), ?C(", "), - ?ACT("top/roster/500", "500") ])] + ?XE(<<"tr">>, + [?XE(<<"td">>, [?CT(<<"Top rosters">>)]), + ?XE(<<"td">>, [ + ?ACT(<<"top/roster/30">>, <<"30">>), ?C(<<", ">>), + ?ACT(<<"top/roster/100">>, <<"100">>), ?C(<<", ">>), + ?ACT(<<"top/roster/500">>, <<"500">>) ])] ) ]) ]), - ?XC("h3", "Users"), - ?XAE("table", [], - [?XE("tbody", [ + ?XC(<<"h3">>, <<"Users">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(global, Lang, "onlineusers"), do_stat(global, Lang, "offlinemsg"), - ?XE("tr", - [?XE("td", [?CT("Top offline message queues") ]), - ?XE("td", [ - ?ACT("top/offlinemsg/30", "30"), ?C(", "), - ?ACT("top/offlinemsg/100", "100"), ?C(", "), - ?ACT("top/offlinemsg/500", "500") ])] + ?XE(<<"tr">>, + [?XE(<<"td">>, [?CT(<<"Top offline message queues">>) ]), + ?XE(<<"td">>, [ + ?ACT(<<"top/offlinemsg/30">>, <<"30">>), ?C(<<", ">>), + ?ACT(<<"top/offlinemsg/100">>, <<"100">>), ?C(<<", ">>), + ?ACT(<<"top/offlinemsg/500">>, <<"500">>) ])] ), do_stat(global, Lang, "vcards"), - ?XE("tr", - [?XE("td", [?CT("Top vCard sizes") ]), - ?XE("td", [ - ?ACT("top/vcard/5", "5"), ?C(", "), - ?ACT("top/vcard/30", "30"), ?C(", "), - ?ACT("top/vcard/100", "100"), ?C(", "), - ?ACT("top/vcard/500", "500") ])] + ?XE(<<"tr">>, + [?XE(<<"td">>, [?CT(<<"Top vCard sizes">>) ]), + ?XE(<<"td">>, [ + ?ACT(<<"top/vcard/5">>, <<"5">>), ?C(<<", ">>), + ?ACT(<<"top/vcard/30">>, <<"30">>), ?C(<<", ">>), + ?ACT(<<"top/vcard/100">>, <<"100">>), ?C(<<", ">>), + ?ACT(<<"top/vcard/500">>, <<"500">>) ])] ) ]) ]), - ?XC("h3", "MUC"), - ?XAE("table", [], - [?XE("tbody", [ + ?XC(<<"h3">>, <<"MUC">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(global, Lang, "totalmucrooms"), do_stat(global, Lang, "permmucrooms"), do_stat(global, Lang, "regmucrooms") ]) ]), - ?XC("h3", "Pub/Sub"), - ?XAE("table", [], - [?XE("tbody", [ + ?XC(<<"h3">>, <<"Pub/Sub">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(global, Lang, "regpubsubnodes") ]) ]), @@ -1039,87 +1044,90 @@ web_page_main(_, #request{path=["statsdx"], lang = Lang} = _Request) -> %% [?XE("tbody", [ %% ]) %% ]), - ?XC("h3", "Sessions: " ++ get_stat_n("client")), - ?XAE("table", [], - [?XE("tbody", + ?XC(<<"h3">>, <<"Sessions: ", (get_stat_n("client"))/binary>>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, do_stat_table(global, Lang, "client", server) ) ]), - ?XC("h3", "Sessions: " ++ get_stat_n("os")), - ?XAE("table", [], - [?XE("tbody", + ?XC(<<"h3">>, <<"Sessions: ", (get_stat_n("os"))/binary>>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, do_stat_table(global, Lang, "os", server) ) ]), - ?XC("h3", "Sessions: " ++ get_stat_n("client") ++ "/" ++ get_stat_n("os")), - ?XAE("table", [], - [?XE("tbody", + ?XC(<<"h3">>, <<"Sessions: ", (get_stat_n("client"))/binary, "/", (get_stat_n("os"))/binary>>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, do_stat_table(global, Lang, "client_os", server) ) ]), - ?XC("h3", "Sessions: " ++ get_stat_n("conntype")), - ?XAE("table", [], - [?XE("tbody", + ?XC(<<"h3">>, <<"Sessions: ", (get_stat_n("conntype"))/binary>>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, do_stat_table(global, Lang, "conntype", server) ) ]), - ?XC("h3", "Sessions: " ++ get_stat_n("client") ++ "/" ++ get_stat_n("conntype")), - ?XAE("table", [], - [?XE("tbody", + ?XC(<<"h3">>, <<"Sessions: ", (get_stat_n("client"))/binary, "/", (get_stat_n("conntype"))/binary>>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, do_stat_table(global, Lang, "client_conntype", server) ) ]), - ?XC("h3", "Sessions: " ++ get_stat_n("languages")), - ?XAE("table", [], - [?XE("tbody", + ?XC(<<"h3">>, <<"Sessions: ", (get_stat_n("languages"))/binary>>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, do_stat_table(global, Lang, "languages", server) ) ]) ], {stop, Res}; -web_page_main(_, #request{path=["statsdx", "top", Topic, Topnumber], q = _Q, lang = Lang} = _Request) -> - Res = [?XC("h1", ?T("Statistics")++" Dx"), +web_page_main(_, #request{path=[<<"statsdx">>, <<"top">>, Topic, Topnumber], q = _Q, lang = Lang} = _Request) -> + Res = [?XC(<<"h1">>, <<(?T(<<"Statistics">>))/binary, " Dx">>), case Topic of - "offlinemsg" -> ?XCT("h2", "Top offline message queues"); - "vcard" -> ?XCT("h2", "Top vCard sizes"); - "roster" -> ?XCT("h2", "Top rosters") + <<"offlinemsg">> -> ?XCT(<<"h2">>, <<"Top offline message queues">>); + <<"vcard">> -> ?XCT(<<"h2">>, <<"Top vCard sizes">>); + <<"roster">> -> ?XCT(<<"h2">>, <<"Top rosters">>) end, - ?XE("table", - [?XE("thead", [?XE("tr", - [?XE("td", [?CT("#")]), - ?XE("td", [?CT("Jabber ID")]), - ?XE("td", [?CT("Value")])] + ?XE(<<"table">>, + [?XE(<<"thead">>, [?XE(<<"tr">>, + [?XE(<<"td">>, [?CT(<<"#">>)]), + ?XE(<<"td">>, [?CT(<<"Jabber ID">>)]), + ?XE(<<"td">>, [?CT(<<"Value">>)])] )]), - ?XE("tbody", do_top_table(global, Lang, Topic, Topnumber, server)) + ?XE(<<"tbody">>, do_top_table(global, Lang, Topic, Topnumber, server)) ]) ], {stop, Res}; -web_page_main(_, #request{path=["statsdx" | FilterURL], q = Q, lang = Lang} = _Request) -> +web_page_main(_, #request{path=[<<"statsdx">> | FilterURL], q = Q, lang = Lang} = _Request) -> Filter = parse_url_filter(FilterURL), Sort_query = get_sort_query(Q), - Res = [?XC("h1", ?T("Statistics")++" Dx"), - ?XC("h2", "Sessions with: "++ io_lib:format("~p", [Filter])), - ?XE("table", + FilterS = io_lib:format("~p", [Filter]), + Res = [?XC(<<"h1">>, list_to_binary(?T("Statistics") ++ " Dx222")), + ?XC(<<"h2">>, list_to_binary("Sessions with: " ++ FilterS)), + ?XE(<<"table">>, [ - ?XE("thead", [?XE("tr", make_sessions_table_tr(Lang) )]), - ?XE("tbody", do_sessions_table(global, Lang, Filter, Sort_query, server)) + ?XE(<<"thead">>, [?XE(<<"tr">>, make_sessions_table_tr(Lang) )]), + ?XE(<<"tbody">>, do_sessions_table(global, Lang, Filter, Sort_query, server)) ]) ], {stop, Res}; web_page_main(Acc, _) -> Acc. -do_top_table(_Node, Lang, Topic, TopnumberString, Host) -> - List = get_top_users(Host, list_to_integer(TopnumberString), Topic), +do_top_table(_Node, Lang, Topic, TopnumberBin, Host) -> + List = get_top_users(Host, list_to_integer(binary_to_list(TopnumberBin)), Topic), %% get_top_users(Topnumber, "roster") {List2, _} = lists:mapfoldl( - fun({Value, User, Server}, Counter) -> + fun({Value, UserB, ServerB}, Counter) -> + User = binary_to_list(UserB), + Server = binary_to_list(ServerB), UserJID = User++"@"++Server, UserJIDUrl = "/admin/server/" ++ Server ++ "/user/" ++ User ++ "/", ValueString = integer_to_list(Value), ValueEl = case Topic of - "offlinemsg" -> {url, UserJIDUrl++"queue/", ValueString}; - "vcard" -> {url, UserJIDUrl++"vcard/", ValueString}; - "roster" -> {url, UserJIDUrl++"roster/", ValueString}; + <<"offlinemsg">> -> {url, UserJIDUrl++"queue/", ValueString}; + <<"vcard">> -> {url, UserJIDUrl++"vcard/", ValueString}; + <<"roster">> -> {url, UserJIDUrl++"roster/", ValueString}; _ -> ValueString end, {do_table_element(Counter, Lang, UserJID, {fixed_url, UserJIDUrl}, ValueEl), @@ -1145,23 +1153,23 @@ get_sort_query2(Q) -> false -> {ok, {reverse, abs(Integer)}} end. make_sessions_table_tr(Lang) -> - Titles = ["Jabber ID", - "Client ID", - "OS ID", - "Lang", - "Connection", - "Client", - "Version", - "OS"], + Titles = [<<"Jabber ID">>, + <<"Client ID">>, + <<"OS ID">>, + <<"Lang">>, + <<"Connection">>, + <<"Client">>, + <<"Version">>, + <<"OS">>], {Titles_TR, _} = lists:mapfoldl( fun(Title, Num_column) -> - NCS = integer_to_list(Num_column), - TD = ?XE("td", [?CT(Title), + NCS = list_to_binary(integer_to_list(Num_column)), + TD = ?XE(<<"td">>, [?CT(Title), ?BR, - ?ACT("?sort="++NCS, "<"), - ?C(" "), - ?ACT("?sort=-"++NCS, ">")]), + ?ACT(<<"?sort=", NCS/binary>>, <<"<">>), + ?C(<<" ">>), + ?ACT(<<"?sort=-", NCS/binary>>, <<">">>)]), {TD, Num_column+1} end, 1, @@ -1178,7 +1186,7 @@ parse_url_filter(_, Res) -> Res. -web_page_node(_, Node, ["statsdx"], _Query, Lang) -> +web_page_node(_, Node, [<<"statsdx">>], _Query, Lang) -> TransactionsCommited = rpc:call(Node, mnesia, system_info, [transaction_commits]), TransactionsAborted = @@ -1189,10 +1197,10 @@ web_page_node(_, Node, ["statsdx"], _Query, Lang) -> rpc:call(Node, mnesia, system_info, [transaction_log_writes]), Res = - [?XC("h1", io_lib:format(?T("~p statistics"), [Node])), - ?XC("h3", "Connections"), - ?XAE("table", [], - [?XE("tbody", [ + [?XC(<<"h1">>, list_to_binary(io_lib:format(?T("~p statistics"), [Node]))), + ?XC(<<"h3">>, <<"Connections">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(global, Lang, "onlineusers"), do_stat(Node, Lang, "httppollusers"), do_stat(Node, Lang, "httpbindusers"), @@ -1200,15 +1208,15 @@ web_page_node(_, Node, ["statsdx"], _Query, Lang) -> do_stat(Node, Lang, "s2sservers") ]) ]), - ?XC("h3", "ejabberd"), - ?XAE("table", [], - [?XE("tbody", [ + ?XC(<<"h3">>, <<"ejabberd">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(Node, Lang, "ejabberdversion") ]) ]), - ?XC("h3", "Erlang"), - ?XAE("table", [], - [?XE("tbody", [ + ?XC(<<"h3">>, <<"Erlang">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(Node, Lang, "operatingsystem"), do_stat(Node, Lang, "erlangmachine"), do_stat(Node, Lang, "erlangmachinetarget"), @@ -1217,18 +1225,18 @@ web_page_node(_, Node, ["statsdx"], _Query, Lang) -> do_stat(Node, Lang, "totalerlproc") ]) ]), - ?XC("h3", "Times"), - ?XAE("table", [], - [?XE("tbody", [ + ?XC(<<"h3">>, <<"Times">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(Node, Lang, "uptime"), do_stat(Node, Lang, "uptimehuman"), do_stat(Node, Lang, "lastrestart"), do_stat(Node, Lang, "cputime") ]) ]), - ?XC("h3", "CPU"), - ?XAE("table", [], - [?XE("tbody", [ + ?XC(<<"h3">>, <<"CPU">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(Node, Lang, "cpu_avg1"), do_stat(Node, Lang, "cpu_avg5"), do_stat(Node, Lang, "cpu_avg15"), @@ -1248,9 +1256,9 @@ web_page_node(_, Node, ["statsdx"], _Query, Lang) -> %% do_stat(Node, Lang, "reductions") %%]) %%]), - ?XC("h3", "Memory (bytes)"), - ?XAE("table", [], - [?XE("tbody", [ + ?XC(<<"h3">>, <<"Memory (bytes)">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(Node, Lang, "memory_total"), do_stat(Node, Lang, "memory_processes"), do_stat(Node, Lang, "memory_processes_used"), @@ -1262,84 +1270,84 @@ web_page_node(_, Node, ["statsdx"], _Query, Lang) -> do_stat(Node, Lang, "memory_ets") ]) ]), - ?XC("h3", "Database"), - ?XAE("table", [], - [?XE("tbody", + ?XC(<<"h3">>, <<"Database">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ - ?XE("tr", [?XCT("td", "Transactions commited"), - ?XAC("td", [{"class", "alignright"}], - integer_to_list(TransactionsCommited))]), - ?XE("tr", [?XCT("td", "Transactions aborted"), - ?XAC("td", [{"class", "alignright"}], - integer_to_list(TransactionsAborted))]), - ?XE("tr", [?XCT("td", "Transactions restarted"), - ?XAC("td", [{"class", "alignright"}], - integer_to_list(TransactionsRestarted))]), - ?XE("tr", [?XCT("td", "Transactions logged"), - ?XAC("td", [{"class", "alignright"}], - integer_to_list(TransactionsLogged))]) + ?XE(<<"tr">>, [?XCT(<<"td">>, <<"Transactions commited">>), + ?XAC(<<"td">>, [{<<"class">>, <<"alignright">>}], + list_to_binary(integer_to_list(TransactionsCommited)))]), + ?XE(<<"tr">>, [?XCT(<<"td">>, <<"Transactions aborted">>), + ?XAC(<<"td">>, [{<<"class">>, <<"alignright">>}], + list_to_binary(integer_to_list(TransactionsAborted)))]), + ?XE(<<"tr">>, [?XCT(<<"td">>, <<"Transactions restarted">>), + ?XAC(<<"td">>, [{<<"class">>, <<"alignright">>}], + list_to_binary(integer_to_list(TransactionsRestarted)))]), + ?XE(<<"tr">>, [?XCT(<<"td">>, <<"Transactions logged">>), + ?XAC(<<"td">>, [{<<"class">>, <<"alignright">>}], + list_to_binary(integer_to_list(TransactionsLogged)))]) ]) ])], {stop, Res}; web_page_node(Acc, _, _, _, _) -> Acc. web_page_host(_, Host, - #request{path = ["statsdx"], + #request{path = [<<"statsdx">>], lang = Lang} = _Request) -> - Res = [?XC("h1", ?T("Statistics")++" Dx"), - ?XC("h2", Host), - ?XC("h3", "Accounts"), - ?XAE("table", [], - [?XE("tbody", [ + Res = [?XC(<<"h1">>, <<(?T(<<"Statistics">>))/binary, " Dx">>), + ?XC(<<"h2">>, Host), + ?XC(<<"h3">>, <<"Accounts">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(global, Lang, "registeredusers", Host) ]) ]), - ?XC("h3", "Roster"), - ?XAE("table", [], - [?XE("tbody", [ + ?XC(<<"h3">>, <<"Roster">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(global, Lang, "totalrosteritems", Host), %%get_meanitemsinroster2(TotalRosterItems, RegisteredUsers) - ?XE("tr", - [?XE("td", [?C("Top rosters") ]), - ?XE("td", [ - ?ACT("top/roster/30", "30"), ?C(", "), - ?ACT("top/roster/100", "100"), ?C(", "), - ?ACT("top/roster/500", "500") ])] + ?XE(<<"tr">>, + [?XE(<<"td">>, [?C(<<"Top rosters">>) ]), + ?XE(<<"td">>, [ + ?ACT(<<"top/roster/30">>, <<"30">>), ?C(<<", ">>), + ?ACT(<<"top/roster/100">>, <<"100">>), ?C(<<", ">>), + ?ACT(<<"top/roster/500">>, <<"500">>) ])] ) ]) ]), - ?XC("h3", "Users"), - ?XAE("table", [], - [?XE("tbody", [ + ?XC(<<"h3">>, <<"Users">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(global, Lang, "onlineusers", Host), %%do_stat(global, Lang, "offlinemsg", Host), %% This make take a lot of time %%do_stat(global, Lang, "vcards", Host) %% This make take a lot of time - ?XE("tr", - [?XE("td", [?C("Top offline message queues")]), - ?XE("td", [ - ?ACT("top/offlinemsg/30", "30"), ?C(", "), - ?ACT("top/offlinemsg/100", "100"), ?C(", "), - ?ACT("top/offlinemsg/500", "500") ])] + ?XE(<<"tr">>, + [?XE(<<"td">>, [?C(<<"Top offline message queues">>)]), + ?XE(<<"td">>, [ + ?ACT(<<"top/offlinemsg/30">>, <<"30">>), ?C(<<", ">>), + ?ACT(<<"top/offlinemsg/100">>, <<"100">>), ?C(<<", ">>), + ?ACT(<<"top/offlinemsg/500">>, <<"500">>) ])] ), - ?XE("tr", - [?XE("td", [?C("Top vCard sizes") ]), - ?XE("td", [ - ?ACT("top/vcard/5", "5"), ?C(", "), - ?ACT("top/vcard/30", "30"), ?C(", "), - ?ACT("top/vcard/100", "100"), ?C(", "), - ?ACT("top/vcard/500", "500") ])] + ?XE(<<"tr">>, + [?XE(<<"td">>, [?C(<<"Top vCard sizes">>) ]), + ?XE(<<"td">>, [ + ?ACT(<<"top/vcard/5">>, <<"5">>), ?C(<<", ">>), + ?ACT(<<"top/vcard/30">>, <<"30">>), ?C(<<", ">>), + ?ACT(<<"top/vcard/100">>, <<"100">>), ?C(<<", ">>), + ?ACT(<<"top/vcard/500">>, <<"500">>) ])] ) ]) ]), - ?XC("h3", "Connections"), - ?XAE("table", [], - [?XE("tbody", [ + ?XC(<<"h3">>, <<"Connections">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(global, Lang, "s2sconnections", Host) ]) ]), - ?XC("h3", "MUC"), - ?XAE("table", [], - [?XE("tbody", [ + ?XC(<<"h3">>, <<"MUC">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(global, Lang, "totalmucrooms", Host), do_stat(global, Lang, "permmucrooms", Host), do_stat(global, Lang, "regmucrooms", Host) @@ -1357,45 +1365,45 @@ web_page_host(_, Host, %% do_stat(global, Lang, "regpubsubnodes", Host) %% ]) %%]), - ?XC("h3", "Sessions: " ++ get_stat_n("client")), - ?XAE("table", [], - [?XE("tbody", + ?XC(<<"h3">>, <<"Sessions: ", (get_stat_n("client"))/binary>>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, do_stat_table(global, Lang, "client", Host) ) ]), - ?XC("h3", "Sessions: " ++ get_stat_n("os")), - ?XAE("table", [], - [?XE("tbody", + ?XC(<<"h3">>, <<"Sessions: ", (get_stat_n("os"))/binary>>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, do_stat_table(global, Lang, "os", Host) ) ]), - ?XC("h3", "Sessions: " ++ get_stat_n("client") ++ "/" ++ get_stat_n("os")), - ?XAE("table", [], - [?XE("tbody", + ?XC(<<"h3">>, <<"Sessions: ", (get_stat_n("client"))/binary, "/", (get_stat_n("os"))/binary>>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, do_stat_table(global, Lang, "client_os", Host) ) ]), - ?XC("h3", "Sessions: " ++ get_stat_n("conntype")), - ?XAE("table", [], - [?XE("tbody", + ?XC(<<"h3">>, <<"Sessions: ", (get_stat_n("conntype"))/binary>>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, do_stat_table(global, Lang, "conntype", Host) ) ]), - ?XC("h3", "Sessions: " ++ get_stat_n("client") ++ "/" ++ get_stat_n("conntype")), - ?XAE("table", [], - [?XE("tbody", + ?XC(<<"h3">>, <<"Sessions: ", (get_stat_n("client"))/binary, "/", (get_stat_n("conntype"))/binary>>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, do_stat_table(global, Lang, "client_conntype", Host) ) ]), - ?XC("h3", "Sessions: " ++ get_stat_n("languages")), - ?XAE("table", [], - [?XE("tbody", + ?XC(<<"h3">>, <<"Sessions: ", (get_stat_n("languages"))/binary>>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, do_stat_table(global, Lang, "languages", Host) ) ]), - ?XC("h3", "Ratios"), - ?XAE("table", [], - [?XE("tbody", [ + ?XC(<<"h3">>, <<"Ratios">>), + ?XAE(<<"table">>, [], + [?XE(<<"tbody">>, [ do_stat(global, Lang, "user_login", Host), do_stat(global, Lang, "user_logout", Host), do_stat(global, Lang, "register_user", Host), @@ -1416,24 +1424,24 @@ web_page_host(_, Host, ]) ], {stop, Res}; -web_page_host(_, Host, #request{path=["statsdx", "top", Topic, Topnumber], q = _Q, lang = Lang} = _Request) -> +web_page_host(_, Host, #request{path=[<<"statsdx">>, <<"top">>, Topic, Topnumber], q = _Q, lang = Lang} = _Request) -> Res = [?XC("h1", ?T("Statistics")++" Dx"), case Topic of - "offlinemsg" -> ?XCT("h2", "Top offline message queues"); - "vcard" -> ?XCT("h2", "Top vCard sizes"); - "roster" -> ?XCT("h2", "Top rosters") + <<"offlinemsg">> -> ?XCT(<<"h2">>, <<"Top offline message queues">>); + <<"vcard">> -> ?XCT(<<"h2">>, <<"Top vCard sizes">>); + <<"roster">> -> ?XCT(<<"h2">>, <<"Top rosters">>) end, - ?XE("table", - [?XE("thead", [?XE("tr", - [?XE("td", [?CT("#")]), - ?XE("td", [?CT("Jabber ID")]), - ?XE("td", [?CT("Value")])] + ?XE(<<"table">>, + [?XE(<<"thead">>, [?XE(<<"tr">>, + [?XE(<<"td">>, [?CT(<<"#">>)]), + ?XE(<<"td">>, [?CT(<<"Jabber ID">>)]), + ?XE(<<"td">>, [?CT(<<"Value">>)])] )]), - ?XE("tbody", do_top_table(global, Lang, Topic, Topnumber, Host)) + ?XE(<<"tbody">>, do_top_table(global, Lang, Topic, Topnumber, Host)) ]) ], {stop, Res}; -web_page_host(_, Host, #request{path=["statsdx" | FilterURL], q = Q, +web_page_host(_, Host, #request{path=[<<"statsdx">> | FilterURL], q = Q, lang = Lang} = _Request) -> Filter = parse_url_filter(FilterURL), Sort_query = get_sort_query(Q), @@ -1455,19 +1463,20 @@ web_page_host(Acc, _, _) -> Acc. do_table_element(Lang, L, StatLink, N) -> do_table_element(no_counter, Lang, L, StatLink, N). do_table_element(Counter, Lang, L, StatLink, N) -> - ?XE("tr", [ + ?XE(<<"tr">>, [ case Counter of - no_counter -> ?C(""); - _ -> ?XE("td", [?C(integer_to_list(Counter))]) + no_counter -> ?C(<<"">>); + _ -> ?XE(<<"td">>, [?C(integer_to_list(Counter))]) end, case StatLink of - no_link -> ?XCT("td", L); - {fixed_url, Fixedurl} -> ?XE("td", [?AC(Fixedurl, L)]); - _ -> ?XE("td", [?AC(make_url(StatLink, L), L)]) + no_link -> ?XCT(<<"td">>, L); + {fixed_url, Fixedurl} -> ?XE(<<"td">>, [?AC(Fixedurl, L)]); + _ -> ?XE(<<"td">>, [?AC(list_to_binary(make_url(StatLink, L)), list_to_binary(L))]) end, case N of - {url, NUrl, NName} -> ?XAE("td", [{"class", "alignright"}], [?AC(NUrl, NName)]); - _ -> ?XAC("td", [{"class", "alignright"}], N) + {url, NUrl, NName} -> ?XAE(<<"td">>, [{<<"class">>, <<"alignright">>}], [?AC(NUrl, NName)]); + N when is_list(N) -> ?XAC(<<"td">>, [{<<"class">>, <<"alignright">>}], list_to_binary(N)); + _ -> ?XAC(<<"td">>, [{<<"class">>, <<"alignright">>}], N) end ]). @@ -1499,14 +1508,14 @@ do_sessions_table(_Node, _Lang, Filter, {Sort_direction, Sort_column}, Host) -> Server = JID#jid.lserver, UserURL = "/admin/server/" ++ Server ++ "/user/" ++ User ++ "/", ?XE("tr", [ - ?XE("td", [?AC(UserURL, jlib:jid_to_string(JID))]), - ?XCT("td", atom_to_list(Client_id)), - ?XCT("td", atom_to_list(OS_id)), - ?XCT("td", Lang), - ?XCT("td", atom_to_list(ConnType)), - ?XCT("td", Client), - ?XCT("td", Version), - ?XCT("td", OS) + ?XE(<<"td">>, [?AC(UserURL, jlib:jid_to_string(JID))]), + ?XCTB("td", atom_to_list(Client_id)), + ?XCTB("td", atom_to_list(OS_id)), + ?XCTB("td", Lang), + ?XCTB("td", atom_to_list(ConnType)), + ?XCTB("td", Client), + ?XCTB("td", Version), + ?XCTB("td", OS) ]) end, SessionsSorted @@ -1544,9 +1553,9 @@ get_sessions_filtered(Filter, Host) -> ets:match_object(table_name(Host), Match). do_stat(Node, Lang, Stat) -> - ?XE("tr", [ - ?XCT("td", get_stat_n(Stat)), - ?XAC("td", [{"class", "alignright"}], + ?XE(<<"tr">>, [ + ?XCT(<<"td">>, get_stat_n(Stat)), + ?XAC(<<"td">>, [{<<"class">>, <<"alignright">>}], get_stat_v(Node, [Stat]))]). do_stat(Node, Lang, Stat, Host) -> @@ -1556,9 +1565,9 @@ do_stat(Node, Lang, Stat, Host) -> %% Get a stat name get_stat_n(Stat) -> - mod_statsdx:get_statistic(foo, [Stat, title]). + list_to_binary(mod_statsdx:get_statistic(foo, [Stat, title])). %% Get a stat value -get_stat_v(Node, Stat) -> get_stat_v2(mod_statsdx:get_statistic(Node, Stat)). +get_stat_v(Node, Stat) -> list_to_binary(get_stat_v2(mod_statsdx:get_statistic(Node, Stat))). get_stat_v2(Value) when is_list(Value) -> Value; get_stat_v2(Value) when is_float(Value) -> io_lib:format("~.4f", [Value]); get_stat_v2(Value) when is_integer(Value) -> @@ -1616,11 +1625,11 @@ get_top_users(Number, Topic) -> get_top_users(server, Number, Topic). %% Returns: [{Integer, User, Server}] -get_top_users(Host, Number, "vcard") -> +get_top_users(Host, Number, <<"vcard">>) -> get_top_users_vcard(Host, Number); -get_top_users(Host, Number, "offlinemsg") -> +get_top_users(Host, Number, <<"offlinemsg">>) -> get_top_users(Host, Number, offline_msg, #offline_msg.us); -get_top_users(Host, Number, "roster") -> +get_top_users(Host, Number, <<"roster">>) -> get_top_users(Host, Number, roster, #roster.us). From 1a17e978739daebeb035363829a69039eebc7bd4 Mon Sep 17 00:00:00 2001 From: Antonio Murdaca Date: Tue, 8 Apr 2014 00:10:05 +0200 Subject: [PATCH 10/13] Refactor mod_webpresence to work with binary plus icons --- mod_webpresence/README.txt | 104 +- mod_webpresence/build.bat | 2 +- .../data/pixmaps/simple/available.png | Bin 0 -> 785 bytes mod_webpresence/data/pixmaps/simple/away.png | Bin 0 -> 837 bytes mod_webpresence/data/pixmaps/simple/chat.png | Bin 0 -> 854 bytes mod_webpresence/data/pixmaps/simple/dnd.png | Bin 0 -> 824 bytes .../data/pixmaps/simple/unavailable.png | Bin 0 -> 681 bytes mod_webpresence/data/pixmaps/simple/xa.png | Bin 0 -> 830 bytes mod_webpresence/src/mod_webpresence.erl | 899 ++++++++++-------- 9 files changed, 568 insertions(+), 437 deletions(-) create mode 100644 mod_webpresence/data/pixmaps/simple/available.png create mode 100644 mod_webpresence/data/pixmaps/simple/away.png create mode 100644 mod_webpresence/data/pixmaps/simple/chat.png create mode 100644 mod_webpresence/data/pixmaps/simple/dnd.png create mode 100644 mod_webpresence/data/pixmaps/simple/unavailable.png create mode 100644 mod_webpresence/data/pixmaps/simple/xa.png diff --git a/mod_webpresence/README.txt b/mod_webpresence/README.txt index 310debf..47cc1e3 100644 --- a/mod_webpresence/README.txt +++ b/mod_webpresence/README.txt @@ -1,8 +1,6 @@ - mod_webpresence - Presence on the Web - Authors: Igor Goryachev, Badlop - Requires: ejabberd SVN (not possible with 1.1.x) + Authors: Igor Goryachev, Badlop, runcom http://www.ejabberd.im/mod_webpresence @@ -35,23 +33,19 @@ No web server, database, additional libraries or programs are required. 3. Copy the directory data/pixmaps to a directory you prefer. 4. Edit ejabberd.cfg and add the HTTP and module definitions: -{listen, [ - ... - {5280, ejabberd_http, [ - ... - {request_handlers, [ - ... - {["presence"], mod_webpresence} - ]} - ]} -]}. -{modules, [ - ... - {mod_webpresence, [ - {pixmaps_path, "/path/to/pixmaps"} - ]} -]}. +listen: + - + port: 5280 + module: ejabberd_http + [...] + request_handlers: + "presence": mod_webpresence + +modules: + [...] + mod_webpresence: + pixmaps_path: "/path/to/pixmaps" 5. Restart ejabberd. If problems appear, remember to always look first the ejabberd log files @@ -102,10 +96,14 @@ In that case, all the output methods are enabled, the icon theme is 'jsf-jabber-text' and RandomID is disabled. The default behaviour is to not have automatic webpresence: - {access, webpresence_auto, [{deny, all}]}. + access: + webpresence_auto: + all: deny For example, if you want all the local users to be automatically enabled in the service: - {access, webpresence_auto, [{allow, local}]}. + access: + webpresence_auto: + local: allow Note that this ACCESS rule is only checked if the user is not registered. So, if the user registers and disables all output methods, @@ -119,50 +117,40 @@ register and disable output methods, you can use the Access configurable paramet Example 1 --------- -{listen, [ - ... - {5280, ejabberd_http, [ - ... - {request_handlers, [ - ... - {["presence"], mod_webpresence} - ]} - ]} -]}. +listen: + - + port: 5280 + module: ejabberd_http + [...] + request_handlers: + "presence": mod_webpresence -{modules, [ - ... - {mod_webpresence, [ - {pixmaps_path, "/path/to/pixmaps"} - ]} -]}. +modules: + [...] + mod_webpresence: + pixmaps_path: "/path/to/pixmaps" Example 2 --------- -{listen, [ - ... - {80, ejabberd_http, [ - ... - {request_handlers, [ - ... - {["status"], mod_webpresence} - ]} - ]} -]}. +listen: + - + port: 80 + module: ejabberd_http + [...] + request_handlers: + "status": mod_webpresence -{modules, [ - ... - {mod_webpresence, [ - {host, "webstatus.@HOST@"}, - {access, local}, - {pixmaps_path, "/path/to/pixmaps"}, - {port, 80}, - {path, "status"}, - {baseurl, "http://www.example.org/status/"} - ]} -]}. +modules: + [...] + mod_webpresence: + host: "webstatus.@HOST@" + access: local + pixmaps_path: "/path/to/pixmaps" + port: 80 + path: "status" + baseurl: "http://www.example.org/status/" USAGE diff --git a/mod_webpresence/build.bat b/mod_webpresence/build.bat index fff9b3b..8ce7043 100644 --- a/mod_webpresence/build.bat +++ b/mod_webpresence/build.bat @@ -1 +1 @@ -erl -pa ../../ejabberd-dev/trunk/ebin -pa ebin -make +erl -pa ../../ejabberd-dev/ebin -pa ebin -make diff --git a/mod_webpresence/data/pixmaps/simple/available.png b/mod_webpresence/data/pixmaps/simple/available.png new file mode 100644 index 0000000000000000000000000000000000000000..ab570114770b6b4764536fe2ef56d93059744231 GIT binary patch literal 785 zcmV+s1Md8ZP)QWckTR zh@$!uLLwN%WZ}q+5pUWXj-fF4z{&e zLYT8?O-#2j)Loy>c{Mg^U0!%N?>U_3_rIKTc)UEHxSU@~Bq3smCKtslu9fEVF;`^ zCRAXJCvo9$$?p)F8jZ}EfAk?UGeFE1A{&`o3BZh0;4zY;&2Z`tp}x8ROUj}3(X=yD zS|UBhhHt}q?*u&Bn*{J0>5v7faSak5?_%C{4qaEuC_s`6U|8l7+1N><^`P&1EkbN3 zfsG)|u0SUEoMd1?!Y{|X^DJ29P6}Xh0h80Ctw?`;fYg@`bW4Tg-+***h{(c0QUMbZ zA6hZzIE|1=NCA^e0X`X$W6kh9t%Kssb|gQw5h;=S{Dh=$U3RzL6uPJ((Lmj@Xb8Z|q~A8xlBI<*|<53J#g4*3Q|OV5!Mu7 zM!lRfOZM`!7l{IVJ|9??h23t4;=T;^yH=w8R1xgA)?z}n8WSC>@Um$cm-b@h>@B1K z8r|V=z-F_-Y&Ju!Y6tBJZR|fE)2|-T=nTWaXf%S(>H1$^T|P*T{@eT$xm)MKP-!Th P00000NkvXXu0mjff@xUT literal 0 HcmV?d00001 diff --git a/mod_webpresence/data/pixmaps/simple/away.png b/mod_webpresence/data/pixmaps/simple/away.png new file mode 100644 index 0000000000000000000000000000000000000000..0d148f3125d433c180ffb96bb947c96d9c840711 GIT binary patch literal 837 zcmV-L1G@Z)P)PHzB zVURhd3^T3FwNf%o{b7HJUW1@AsCne zJ*N_^;{0iZbn`-HCSE>ogxzjuJ&n_ncH?`O9K+ouc&p7q>6KWBcY1<|M9e0O&!5hK z?S~Z;<2J;FZ)H7=X}&1`Bpm%!nCe$x(kug`Oh)=%FP8{yyS}ytHmijN6>y$uJ|QLy z-#S%9K#j?sB208#Msry_62siVjzed*e0c|J??)C?zzLcU;`7k;x)M{CT1<8q!|~xd z##)Z!{uzHNkji%OL~#$6Pt9{c^SicfMth|je)iRo4l3X<nU0!e2mltV?-T{ z;R+uNm3u*VmV-ngclsJB*<>=oXf&cso`fhU|H4+cTA2PninP>IQ=W zI-L$`wHk7n1mT<3A~MjU=bxX+xdU2VqtQUARD#AdKj+u|&72~$@ZaQLxIYWognY@P P00000NkvXXu0mjf3BquD literal 0 HcmV?d00001 diff --git a/mod_webpresence/data/pixmaps/simple/chat.png b/mod_webpresence/data/pixmaps/simple/chat.png new file mode 100644 index 0000000000000000000000000000000000000000..d6fb64c33d7b0246d40e146623d3e19784534bad GIT binary patch literal 854 zcmV-c1F8IpP)eo}K~#90jZKZYDgw&nKiO0I-9pP@v^2vo6=Ufh^0(hrA&wm7UJqcoh3 zrR4%73V8TDprs6SSR5|L_x_vcRK-Kca{)aLnYpMV0n*wC{EoaQF$nNxVz9dbOXF== z9IAx9?+zBa(ok{5ml&ke9b7KsL)yUqB|Ik!qGO3X3`atP(A(gQAEQsH4(egI$*|CQ z9+uJ&VxXsY5TDFKb~6u`)NGnLt$gGe!$I<5Q49t;DzRi)PZ?-o?=8T*S&VTlml#aY zd+^)uSsa_>kJQ3oTyF`bPZA3bv(ThS#l)L3s(lUKR%PQ`mlR*0Ct_6X>oB0;9PGVq zQo!{?fDaP~y>{bdls6g+<1o-B!JIW0pA1y3PX+lAM;8NW>KJ%4C3u?~2T5 z20BXo>65Ta?v2^zK+Ng_F;nk}X|+3yR~Zm;oR)th5!-AwSgls5lrl(;ZKj20*&fVj z_fge$VoJ3YQPx#07*qoM6N<$f_p}HivR!s literal 0 HcmV?d00001 diff --git a/mod_webpresence/data/pixmaps/simple/dnd.png b/mod_webpresence/data/pixmaps/simple/dnd.png new file mode 100644 index 0000000000000000000000000000000000000000..d2bca6c8b5274b6848f0230bc5533dc93a9cf06f GIT binary patch literal 824 zcmV-81IPS{P)W?xi z!XC>tZP;>^IG0N1V+Oq>h+JxrMzt&qDHBQ>Q7cK8*ka~mLh721VoDq3DwZ;9#cT-^ zR45;0KG@WzcDnadn`BWxINa}d;GEy%yO+h9iEZ2NG0 zzhwk#Sic7m-O1Y*g;%m8aLF^6ljd3J2^i>5W2CbjAB?%ExRC_u9)A#%*tufq6-gxA z`Kj>8(|>{HlrJs308einrh2O}*{yn0Q?*}X`*pNv4k9Jm7tAuh6!u3>)H#b*Jk3b_LBH~`OFc6A!eAFw#ktSy0V@)iYlp+*o@==j3#-qz|Xs=8p zViAU`15tFGJ-tLKCcta65z-hxWGAxFToTHh6s<}gTu+2>>4g}n;b6Eb0H#YUq=?wl zzmbX^4hL*D8#L+yWbI$d2rUKcFrwQ;s;$P5W;uq+d@-o@VZ^d{w)Y}Y1H0W0tJMm# z*^H9A`AFHl2+EWGFw2*rTeSq;#f#CDw}5GTrn2`cQv+JvVzIzvGC{A`L#9+!yK zo2Gx7qwaqU+Z;zu2%7}T*mui5pI`@1O&0bq<3?(v`hjE z%XKC|BBfFZg+c+jTn^D_lmsSg0_|oK-C&Smb2_s7M3Zr1zD@rt}YS@G#U+5*}mk$;c!5yRKjR9!e+DaECPW5EEWs5 zJ)gX~g(N`J%Pg#XKF_UsJRVRc6zo5LCUFLWAaJYnPW31Mx=kV?{5SbG!Or@S6a1dB P00000NkvXXu0mjf+94-1 literal 0 HcmV?d00001 diff --git a/mod_webpresence/data/pixmaps/simple/xa.png b/mod_webpresence/data/pixmaps/simple/xa.png new file mode 100644 index 0000000000000000000000000000000000000000..3b65868af51717d4b88458c6e69f776ed75fbb86 GIT binary patch literal 830 zcmV-E1Ht@>P)PHzB zVURhd3^T1{b2ZE6wHpmGa4rL9Xv;#0nnFYpWl6Tg7Be-4)G-~!k{snCmNILFwnPQ> zM_wqrplM5cde7%&qlkLo;k@U-^PKaZ@BMhZ1?&(6D;b|LPK67CUP?mN*Cd4TEsP@z zq_c)`6YqC0(d|R=aX6#SKz@Ec7b(w4kH^~8s+X5sfP1I`b3?V59niyJJdN|m13V@)cDgDJd3kvtct@%$5@q<(V`2to z%=VY#N7ps9RUbpD%op5s=+4<$SepjN9nv3I2U!RX!StoOms!RKs(I=EfMm}$#~<9-wwShyYRkCvdLqXR0H zYKfFnJyV&4p4JM?IhHd66WpCen6_tP*d!%`5pEBn?Lnn7u^5MwlaZ2=!bQpx_l2WT zpM{Zk57_udysx~1@9kQAd!fK!O{m9!!Do+f-DsjzgoqFUb_Q?8$v7bzN{*tZDF;)| zLVRv6K=ZA1OutfL@~ISWZfuyp0zoVm-;+fKqUf9mjYUy7CFS8`T`XF35|n0&P?ami zfRO5W%$EZxCR6IRTwB;iI#$8+}I19Jx`eosJq>6ht+C@*=&YE zuS3kPt&oTN_5br{THFD3w^%GN8jYZw>VN!of5W1Q7yn!Q3vEd6evo|$2LJ#707*qo IM6N<$f|IFi;s5{u literal 0 HcmV?d00001 diff --git a/mod_webpresence/src/mod_webpresence.erl b/mod_webpresence/src/mod_webpresence.erl index 53d3454..238d2c9 100644 --- a/mod_webpresence/src/mod_webpresence.erl +++ b/mod_webpresence/src/mod_webpresence.erl @@ -1,6 +1,6 @@ %%%---------------------------------------------------------------------- %%% File : mod_webpresence.erl -%%% Author : Igor Goryachev , Badlop +%%% Author : Igor Goryachev , Badlop, runcom %%% Purpose : Allow user to show presence in the web %%% Created : 30 Apr 2006 by Igor Goryachev %%% Id : $Id: mod_webpresence.erl 1083 2010-06-01 18:32:55Z badlop $ @@ -17,7 +17,8 @@ stop/1, remove_user/2, web_menu_host/3, web_page_host/3, - process/2]). + process/2 + ]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, @@ -25,8 +26,9 @@ -include("ejabberd.hrl"). -include("jlib.hrl"). --include("web/ejabberd_web_admin.hrl"). --include("web/ejabberd_http.hrl"). +-include("logger.hrl"). +-include("ejabberd_web_admin.hrl"). +-include("ejabberd_http.hrl"). -record(webpresence, {us, ridurl = false, jidurl = false, xml = false, avatar = false, js = false, text = false, icon = "---"}). -record(state, {host, server_host, base_url, access}). @@ -36,7 +38,7 @@ -record(session, {sid, usr, us, priority, info}). -define(PROCNAME, ejabberd_mod_webpresence). --define(PIXMAPS_DIR, "pixmaps"). +-define(PIXMAPS_DIR, <<"pixmaps">>). -define(AUTO_ACL, webpresence_auto). @@ -53,18 +55,13 @@ start_link(Host, Opts) -> start(Host, Opts) -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - ChildSpec = - {Proc, - {?MODULE, start_link, [Host, Opts]}, - temporary, - 1000, - worker, - [?MODULE]}, + ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]}, + temporary, 1000, worker, [?MODULE]}, Default_dir = case code:priv_dir(ejabberd) of {error, _} -> ?PIXMAPS_DIR; Path -> filename:join([Path, ?PIXMAPS_DIR]) end, - Dir = gen_mod:get_opt(pixmaps_path, Opts, Default_dir), + Dir = gen_mod:get_opt(pixmaps_path, Opts, fun(D) -> D end, Default_dir), catch ets:new(pixmaps_dirs, [named_table, public]), ets:insert(pixmaps_dirs, {directory, Dir}), supervisor:start_child(ejabberd_sup, ChildSpec). @@ -92,11 +89,12 @@ init([Host, Opts]) -> {attributes, record_info(fields, webpresence)}]), mnesia:add_table_index(webpresence, ridurl), update_table(), - MyHost = gen_mod:get_opt_host(Host, Opts, "webpresence.@HOST@"), - Access = gen_mod:get_opt(access, Opts, local), - Port = gen_mod:get_opt(port, Opts, 5280), - Path = gen_mod:get_opt(path, Opts, "presence"), - BaseURL = gen_mod:get_opt(baseurl, Opts, io_lib:format("http://~s:~p/~s/",[Host, Port, Path])), + MyHost = gen_mod:get_opt_host(Host, Opts, <<"webpresence.@HOST@">>), + Access = gen_mod:get_opt(access, Opts, fun(O) -> O end, local), + Port = gen_mod:get_opt(port, Opts, fun(O) -> O end, 5280), + Path = gen_mod:get_opt(path, Opts, fun(O) -> O end, <<"presence">>), + BaseURL = gen_mod:get_opt(baseurl, Opts, fun(O) -> O end, + iolist_to_binary(io_lib:format(<<"http://~s:~p/~s/">>, [Host, Port, Path]))), ejabberd_router:register_route(MyHost), ejabberd_hooks:add(remove_user, Host, ?MODULE, remove_user, 50), ejabberd_hooks:add(webadmin_menu_host, Host, ?MODULE, web_menu_host, 50), @@ -179,26 +177,25 @@ code_change(_OldVsn, State, _Extra) -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- - do_route(Host, ServerHost, Access, From, To, Packet, BaseURL) -> case acl:match_rule(ServerHost, Access, From) of allow -> do_route1(Host, From, To, Packet, BaseURL); _ -> - {xmlelement, _Name, Attrs, _Els} = Packet, - Lang = xml:get_attr_s("xml:lang", Attrs), - ErrText = "Access denied by service policy", + #xmlel{attrs = Attrs} = Packet, + Lang = xml:get_attr_s(<<"xml:lang">>, Attrs), + ErrText = <<"Access denied by service policy">>, Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, ErrText)), ejabberd_router:route(To, From, Err) end. do_route1(Host, From, To, Packet, BaseURL) -> - {xmlelement, Name, Attrs, _Els} = Packet, + #xmlel{name = Name, attrs = Attrs} = Packet, case Name of - "iq" -> do_route1_iq(Host, From, To, Packet, BaseURL, jlib:iq_query_info(Packet)); - _ -> case xml:get_attr_s("type", Attrs) of - "error" -> ok; - "result" -> ok; + <<"iq">> -> do_route1_iq(Host, From, To, Packet, BaseURL, jlib:iq_query_info(Packet)); + _ -> case xml:get_attr_s(<<"type">>, Attrs) of + <<"error">> -> ok; + <<"result">> -> ok; _ -> Err = jlib:make_error_reply(Packet, ?ERR_ITEM_NOT_FOUND), ejabberd_router:route(To, From, Err) end @@ -206,8 +203,12 @@ do_route1(Host, From, To, Packet, BaseURL) -> do_route1_iq(_, From, To, _, _, #iq{type = get, xmlns = ?NS_DISCO_INFO, lang = Lang} = IQ) -> - SubEl2 = {xmlelement, "query", [{"xmlns", ?NS_DISCO_INFO}], iq_disco_info(Lang)}, - Res = IQ#iq{type = result, sub_el = [SubEl2]}, + SubEl = #xmlel{ + name = <<"query">>, + attrs = [{<<"xmlns">>, ?NS_DISCO_INFO}], + children = iq_disco_info(Lang) + }, + Res = IQ#iq{type = result, sub_el = [SubEl]}, ejabberd_router:route(To, From, jlib:iq_to_xml(Res)); do_route1_iq(_, _, _, _, _, @@ -216,15 +217,23 @@ do_route1_iq(_, _, _, _, _, do_route1_iq(Host, From, To, _, _, #iq{type = get, xmlns = ?NS_REGISTER, lang = Lang} = IQ) -> - SubEl2 = {xmlelement, "query", [{"xmlns", ?NS_REGISTER}], iq_get_register_info(Host, From, Lang)}, - Res = IQ#iq{type = result, sub_el = [SubEl2]}, + SubEl = #xmlel{ + name = <<"query">>, + attrs = [{<<"xmlns">>, ?NS_DISCO_INFO}], + children = iq_get_register_info(Host, From, Lang) + }, + Res = IQ#iq{type = result, sub_el = [SubEl]}, ejabberd_router:route(To, From, jlib:iq_to_xml(Res)); do_route1_iq(Host, From, To, Packet, BaseURL, #iq{type = set, xmlns = ?NS_REGISTER, lang = Lang, sub_el = SubEl} = IQ) -> case process_iq_register_set(From, SubEl, Host, BaseURL, Lang) of {result, IQRes} -> - SubEl2 = {xmlelement, "query", [{"xmlns", ?NS_REGISTER}], IQRes}, + SubEl2 = #xmlel{ + name = <<"query">>, + attrs = [{<<"xmlns">>, ?NS_REGISTER}], + children = IQRes + }, Res = IQ#iq{type = result, sub_el = [SubEl2]}, ejabberd_router:route(To, From, jlib:iq_to_xml(Res)); {error, Error} -> @@ -234,58 +243,92 @@ do_route1_iq(Host, From, To, Packet, BaseURL, do_route1_iq(_Host, From, To, _, _, #iq{type = get, xmlns = ?NS_VCARD = XMLNS} = IQ) -> - SubEl2 = {xmlelement, "vCard", [{"xmlns", XMLNS}], iq_get_vcard()}, - Res = IQ#iq{type = result, sub_el = [SubEl2]}, + SubEl = #xmlel{ + name = <<"vCard">>, + attrs = [{<<"xmlns">>, XMLNS}], + children = iq_get_vcard() + }, + Res = IQ#iq{type = result, sub_el = [SubEl]}, ejabberd_router:route(To, From, jlib:iq_to_xml(Res)); do_route1_iq(_Host, From, To, Packet, _, #iq{}) -> - Err = jlib:make_error_reply( Packet, ?ERR_FEATURE_NOT_IMPLEMENTED), + Err = jlib:make_error_reply(Packet, ?ERR_FEATURE_NOT_IMPLEMENTED), ejabberd_router:route(To, From, Err); do_route1_iq(_, _, _, _, _, _) -> ok. iq_disco_info(Lang) -> - [{xmlelement, "identity", - [{"category", "component"}, - {"type", "presence"}, - {"name", ?T("Web Presence")}], []}, - {xmlelement, "feature", [{"var", ?NS_REGISTER}], []}, - {xmlelement, "feature", [{"var", ?NS_VCARD}], []}]. + [#xmlel{ + name = <<"identity">>, + attrs = [{<<"category">>, <<"component">>}, + {<<"type">>, <<"presence">>}, + {<<"name">>, ?T(<<"Web Presence">>)}], + children = [] + }, + #xmlel{ + name = <<"feature">>, + attrs = [{<<"var">>, ?NS_REGISTER}], + children = [] + }, + #xmlel{ + name = <<"feature">>, + attrs = [{<<"var">>, ?NS_VCARD}], + children = [] + }]. -define(XFIELDS(Type, Label, Var, Vals), - {xmlelement, "field", [{"type", Type}, - {"label", ?T(Label)}, - {"var", Var}], - Vals}). + #xmlel{ + name = <<"field">>, + attrs = [ + {<<"type">>, Type}, + {<<"label">>, ?T(Label)}, + {<<"var">>, Var} + ], + children = Vals + }). -define(XFIELD(Type, Label, Var, Val), - ?XFIELDS(Type, Label, Var, - [{xmlelement, "value", [], [{xmlcdata, Val}]}]) + ?XFIELDS(Type, Label, Var, + [ + #xmlel{ + name = <<"value">>, + attrs = [], + children = [{xmlcdata, Val}] + }]) ). -define(XFIELDFIXED(Val), - {xmlelement, "field", [{"type", "fixed"}], - [{xmlelement, "value", [], [{xmlcdata, Val}]}]} + #xmlel{ + name = <<"field">>, + attrs = [{<<"type">>, <<"fixed">>}], + children = [ + #xmlel{ + name = <<"value">>, + attrs = [], + children = [{xmlcdata, Val}] + } + ] + } ). -%% @spec ridurl_out(ridurl()) -> boolean_string() -%% @type ridurl() = string() | false -%% @type boolean_string() = "true" | "false" -ridurl_out(false) -> "false"; -ridurl_out(Id) when is_list(Id) -> "true". +-define(ATOM2BINARY(Val), iolist_to_binary(atom_to_list(Val))). +-define(BC(L), iolist_to_binary(L)). -to_bool("false") -> false; -to_bool("true") -> true; -to_bool("0") -> false; -to_bool("1") -> true. +ridurl_out(false) -> <<"false">>; +ridurl_out(Id) when is_binary(Id) -> <<"true">>. + +to_bool(<<"false">>) -> false; +to_bool(<<"true">>) -> true; +to_bool(<<"0">>) -> false; +to_bool(<<"1">>) -> true. get_pr(LUS) -> case catch mnesia:dirty_read(webpresence, LUS) of [#webpresence{jidurl = J, ridurl = H, xml = X, avatar = A, js = S, text = T, icon = I}] -> {J, H, X, A, S, T, I, true}; _ -> - {true, false, false, false, false, false, "---", false} + {true, false, false, false, false, false, <<"---">>, false} end. get_pr_rid(LUS) -> @@ -296,40 +339,69 @@ iq_get_register_info(_Host, From, Lang) -> {LUser, LServer, _} = jlib:jid_tolower(From), LUS = {LUser, LServer}, {JidUrl, RidUrl, XML, Avatar, JS, Text, Icon, Registered} = get_pr(LUS), - RegisteredXML = case Registered of - true -> [{xmlelement, "registered", [], []}]; + RegisteredXML = case Registered of + true -> [#xmlel{name = <<"registered">>, attrs = [], children = []}]; false -> [] end, RegisteredXML ++ - [{xmlelement, "instructions", [], - [{xmlcdata, ?T("You need an x:data capable client to register presence")}]}, - {xmlelement, "x", - [{"xmlns", ?NS_XDATA}], - [{xmlelement, "title", [], - [{xmlcdata, - ?T("Web Presence")}]}, - {xmlelement, "instructions", [], [{xmlcdata, ?T("What features do you want to enable?")}]}, - ?XFIELDFIXED(?T("URL Type")++". "++?T("Select one at least")), - ?XFIELD("boolean", "Jabber ID", "jidurl", atom_to_list(JidUrl)), - ?XFIELD("boolean", "Random ID", "ridurl", ridurl_out(RidUrl)), - ?XFIELDFIXED(?T("Output Type")++". "++?T("Select one at least")), - ?XFIELDS("list-single", ?T("Icon Theme"), "icon", - [{xmlelement, "value", [], [{xmlcdata, Icon}]}, - {xmlelement, "option", [{"label", "---"}], - [{xmlelement, "value", [], [{xmlcdata, "---"}]}]} - ] ++ available_themes(xdata) - ), - ?XFIELD("boolean", "XML", "xml", atom_to_list(XML)), - ?XFIELD("boolean", "JavaScript", "js", atom_to_list(JS)), - ?XFIELD("boolean", "Text", "text", atom_to_list(Text)), - ?XFIELD("boolean", "Avatar", "avatar", atom_to_list(Avatar))]}]. + [ + #xmlel{ + name = <<"instructions">>, + attrs = [], + children = [{xmlcdata, ?T(<<"You need an x:data capable client to register presence">>)}] + }, + #xmlel{ + name = <<"x">>, + attrs = [{<<"xmlns">>, ?NS_XDATA}], + children = [ + #xmlel{ + name = <<"title">>, + attrs = [], + children = [{xmlcdata, ?T(<<"Web Presence">>)}] + }, + #xmlel{ + name = <<"instructions">>, + attrs = [], + children = [{xmlcdata, ?T(<<"What features do you want to enable?">>)}] + }, + ?XFIELDFIXED(?BC([?T(<<"URL Type">>), <<". ">>, ?T(<<"Select one at least">>)])), + ?XFIELD(<<"boolean">>, <<"Jabber ID">>, <<"jidurl">>, ?ATOM2BINARY(JidUrl)), + ?XFIELD(<<"boolean">>, <<"Random ID">>, <<"ridurl">>, ridurl_out(RidUrl)), + ?XFIELDFIXED(?BC([?T(<<"Output Type">>), <<". ">>, ?T(<<"Select one at least">>)])), + ?XFIELDS(<<"list-single">>, ?T(<<"Icon Theme">>), <<"icon">>, + [ + #xmlel{ + name = <<"value">>, + attrs = [], + children = [{xmlcdata, Icon}] + }, + #xmlel{ + name = <<"option">>, + attrs = [{<<"label">>, <<"---">>}], + children = [ + #xmlel{ + name = <<"value">>, + attrs = [], + children = [{xmlcdata, <<"---">>}] + } + ] + } + ] ++ available_themes(xdata) + ), + ?XFIELD(<<"boolean">>, <<"XML">>, <<"xml">>, ?ATOM2BINARY(XML)), + ?XFIELD(<<"boolean">>, <<"JavaScript">>, <<"js">>, ?ATOM2BINARY(JS)), + ?XFIELD(<<"boolean">>, <<"Text">>, <<"text">>, ?ATOM2BINARY(Text)), + ?XFIELD(<<"boolean">>, <<"Avatar">>, <<"avatar">>, ?ATOM2BINARY(Avatar)) + ] + } + ]. -%% TODO: Check if remote users are allowed to reach here: they should not be allowed +%%%% TODO: Check if remote users are allowed to reach here: they should not be allowed iq_set_register_info(From, {Host, JidUrl, RidUrl, XML, Avatar, JS, Text, Icon, _, Lang} = Opts) -> {LUser, LServer, _} = jlib:jid_tolower(From), LUS = {LUser, LServer}, Check_URLTypes = (JidUrl == true) or (RidUrl =/= false), - Check_OutputTypes = (XML == true) or (Avatar == true) or (JS == true) or (Text == true) or (Icon =/= "---"), + Check_OutputTypes = (XML == true) or (Avatar == true) or (JS == true) or (Text == true) or (Icon =/= <<"---">>), case Check_URLTypes and Check_OutputTypes of true -> iq_set_register_info2(From, LUS, Opts); false -> unregister_webpresence(From, Host, Lang) @@ -358,93 +430,110 @@ get_rid_final_value(false, _) -> false; get_rid_final_value(true, {U, S} = LUS) -> case get_pr_rid(LUS) of false -> - integer_to_list(erlang:phash2(U) * erlang:phash2(S) + iolist_to_binary(integer_to_list(erlang:phash2(U) * erlang:phash2(S) * calendar:datetime_to_gregorian_seconds( - calendar:local_time())) - ++ randoms:get_string(); - H when is_list(H) -> + calendar:local_time())) + ++ randoms:get_string()); + H when is_binary(H) -> H end. send_message_registered(WP, To, Host, BaseURL, Lang) -> {User, Server} = WP#webpresence.us, - JID = jlib:make_jid(User, Server, ""), + JID = jlib:make_jid(User, Server, <<"">>), JIDS = jlib:jid_to_string(JID), Oavatar = case WP#webpresence.avatar of - false -> ""; - true -> " avatar\n" - " avatar/my.png\n" + false -> <<"">>; + true -> <<" avatar\n" + " avatar/my.png\n">> end, Ojs = case WP#webpresence.js of - false -> ""; - true -> " js\n" + false -> <<"">>; + true -> <<" js\n">> end, Otext = case WP#webpresence.text of - false -> ""; - true -> " text\n" - " text/res/<"++?T("Resource")++">\n" + false -> <<"">>; + true -> ?BC([ + <<" text\n" + " text/res/<">>, ?T(<<"Resource">>), <<">\n">> + ]) end, Oimage = case WP#webpresence.icon of - "---" -> ""; - I when is_list(I) -> - " image\n" - " image/example.php\n" - " image/mypresence.png\n" - " image/res/<"++?T("Resource")++">\n" - " image/theme/<"++?T("Icon Theme")++">\n" - " image/theme/<"++?T("Icon Theme")++">/res/<"++?T("Resource")++">\n" + <<"---">> -> ""; + I when is_binary(I) -> + ?BC([ + <<" image\n" + " image/example.php\n" + " image/mypresence.png\n" + " image/res/<">>, ?T(<<"Resource">>), <<">\n" + " image/theme/<">>, ?T(<<"Icon Theme">>), <<">\n" + " image/theme/<">>, ?T(<<"Icon Theme">>), <<">/res/<">>, ?T(<<"Resource">>), <<">\n">> + ]) end, Oxml = case WP#webpresence.xml of - false -> ""; - true -> " xml\n" + false -> <<"">>; + true -> <<" xml\n">> end, Allowed_type = case {Oimage, Oxml, Oavatar, Otext, Ojs} of - {"", "", "", "", _} -> "js"; - {"", "", "", _, _} -> "text"; - {"", "", _, _, _} -> "avatar"; - {"", _, _, _, _} -> "xml"; - {_, _, _, _, _} -> "image" + {<<"">>, <<"">>, <<"">>, <<"">>, _} -> <<"js">>; + {<<"">>, <<"">>, <<"">>, _, _} -> <<"text">>; + {<<"">>, <<"">>, _, _, _} -> <<"avatar">>; + {<<"">>, _, _, _, _} -> <<"xml">>; + {_, _, _, _, _} -> <<"image">> end, {USERID_jid, Example_jid} = case WP#webpresence.jidurl of - false -> {"", ""}; - true -> - JIDT = "jid/"++User++"/"++Server, - {" "++JIDT++"\n", - " "++BaseURL++JIDT++"/"++Allowed_type++"/\n"} + false -> {<<"">>, <<"">>}; + true -> + JIDT = ?BC([<<"jid/">>, User, <<"/">>, Server]), + {?BC([<<" ">>, JIDT, <<"\n">>]), + ?BC([<<" ">>, BaseURL, JIDT, <<"/">>, Allowed_type, <<"/\n">>])} end, {USERID_rid, Example_rid, Text_rid} = case WP#webpresence.ridurl of - false -> {"", "", ""}; - RID when is_list(RID) -> - RIDT = "rid/"++RID, - {" "++RIDT++"\n", - " "++BaseURL++RIDT++"/"++Allowed_type++"/\n", - ?T("If you forget your RandomID, register again to receive this message.")++"\n" - ++?T("To get a new RandomID, disable the option and register again.")++"\n" + false -> {<<"">>, <<"">>, <<"">>}; + RID when is_binary(RID) -> + RIDT = ?BC([<<"rid/">>, RID]), + {?BC([<<" ">>, RIDT, <<"\n">>]), + ?BC([<<" ">>, BaseURL, RIDT, <<"/">>, Allowed_type, <<"/\n">>]), + ?BC([?T(<<"If you forget your RandomID, register again to receive this message.">>), <<"\n">>, + ?T(<<"To get a new RandomID, disable the option and register again.">>), <<"\n">>]) } end, - Subject = ?T("Web Presence")++": "++?T("registered"), - Body = ?T("You have registered:")++" "++JIDS++"\n\n" - ++?T("Use URLs like:")++"\n" - " "++BaseURL++"USERID/OUTPUT/\n" - "\n" - "USERID:\n"++USERID_jid++USERID_rid++"\n" - "OUTPUT:\n"++Oimage++Oxml++Ojs++Otext++Oavatar++"\n" - ++?T("Example:")++"\n"++Example_jid++Example_rid++"\n" - ++Text_rid, + Subject = ?BC([?T(<<"Web Presence">>), <<": ">>, ?T(<<"registered">>)]), + Body = ?BC([?T(<<"You have registered:">>), <<" ">>, JIDS, <<"\n\n">>, + ?T(<<"Use URLs like:">>), <<"\n">>, + <<" ">>, BaseURL, <<"USERID/OUTPUT/\n">>, + <<"\n">>, + <<"USERID:\n">>, USERID_jid, USERID_rid, <<"\n">>, + <<"OUTPUT:\n">>, Oimage, Oxml, Ojs, Otext, Oavatar, <<"\n">>, + ?T(<<"Example:">>), <<"\n">>, Example_jid, Example_rid, <<"\n">>, + Text_rid]), send_headline(Host, To, Subject, Body). send_message_unregistered(To, Host, Lang) -> - Subject = ?T("Web Presence")++": "++?T("unregistered"), - Body = ?T("You have unregistered.")++"\n\n", + Subject = ?BC([?T(<<"Web Presence">>), <<": ">>, ?T(<<"unregistered">>)]), + Body = ?BC([?T(<<"You have unregistered.">>), <<"\n\n">>]), send_headline(Host, To, Subject, Body). send_headline(Host, To, Subject, Body) -> ejabberd_router:route( - jlib:make_jid("", Host, ""), + jlib:make_jid(<<"">>, Host, <<"">>), To, - {xmlelement, "message", [{"type", "headline"}], - [{xmlelement, "subject", [], [{xmlcdata, Subject}]}, - {xmlelement, "body", [], [{xmlcdata, Body}]}]}). + #xmlel{ + name = <<"message">>, + attrs = [{<<"type">>, <<"headline">>}], + children = [ + #xmlel{ + name = <<"subject">>, + attrs = [], + children = [{xmlcdata, Subject}] + }, + #xmlel{ + name = <<"body">>, + attrs = [], + children = [{xmlcdata, Body}] + } + ] + }). get_attr(Attr, XData, Default) -> case lists:keysearch(Attr, 1, XData) of @@ -453,8 +542,8 @@ get_attr(Attr, XData, Default) -> end. process_iq_register_set(From, SubEl, Host, BaseURL, Lang) -> - {xmlelement, _Name, _Attrs, Els} = SubEl, - case xml:get_subtag(SubEl, "remove") of + #xmlel{name = _, attrs = _, children = Els} = SubEl, + case xml:get_subtag(SubEl, <<"remove">>) of false -> case catch process_iq_register_set2(From, Els, Host, BaseURL, Lang) of {'EXIT', _} -> {error, ?ERR_BAD_REQUEST}; R -> R @@ -463,20 +552,26 @@ process_iq_register_set(From, SubEl, Host, BaseURL, Lang) -> end. process_iq_register_set2(From, Els, Host, BaseURL, Lang) -> - [{xmlelement, "x", _Attrs1, _Els1} = XEl] = xml:remove_cdata(Els), - case {xml:get_tag_attr_s("xmlns", XEl), xml:get_tag_attr_s("type", XEl)} of - {?NS_XDATA, "cancel"} -> + [ + #xmlel{ + name = <<"x">>, + attrs = _Attrs1, + children = _Els1 + } = XEl + ] = xml:remove_cdata(Els), + case {xml:get_tag_attr_s(<<"xmlns">>, XEl), xml:get_tag_attr_s(<<"type">>, XEl)} of + {?NS_XDATA, <<"cancel">>} -> {result, []}; - {?NS_XDATA, "submit"} -> + {?NS_XDATA, <<"submit">>} -> XData = jlib:parse_xdata_submit(XEl), false = (invalid == XData), - JidUrl = get_attr("jidurl", XData, "false"), - RidUrl = get_attr("ridurl", XData, "false"), - XML = get_attr("xml", XData, "false"), - Avatar = get_attr("avatar", XData, "false"), - JS = get_attr("js", XData, "false"), - Text = get_attr("text", XData, "false"), - Icon = get_attr("icon", XData, "---"), + JidUrl = get_attr(<<"jidurl">>, XData, <<"false">>), + RidUrl = get_attr(<<"ridurl">>, XData, <<"false">>), + XML = get_attr(<<"xml">>, XData, <<"false">>), + Avatar = get_attr(<<"avatar">>, XData, <<"false">>), + JS = get_attr(<<"js">>, XData, <<"false">>), + Text = get_attr(<<"text">>, XData, <<"false">>), + Icon = get_attr(<<"icon">>, XData, <<"---">>), iq_set_register_info(From, {Host, to_bool(JidUrl), to_bool(RidUrl), to_bool(XML), to_bool(Avatar), to_bool(JS), to_bool(Text), Icon, BaseURL, Lang}) end. @@ -490,52 +585,61 @@ remove_user(User, Server) -> mnesia:dirty_delete(webpresence, {User, Server}). iq_get_vcard() -> - [{xmlelement, "FN", [], - [{xmlcdata, "ejabberd/mod_webpresence"}]}, - {xmlelement, "URL", [], - [{xmlcdata, "http://www.ejabberd.im/mod_webpresence"}]}, - {xmlelement, "DESC", [], - [{xmlcdata, "ejabberd web presence module\nCopyright (c) 2006-2007 Igor Goryachev, 2007 Badlop"}]}]. + [ + #xmlel{ + name = <<"FN">>, + attrs = [], + children = [{xmlcdata, <<"ejabberd/mod_webpresence">>}] + }, + #xmlel{ + name = <<"URL">>, + attrs = [], + children = [{xmlcdata, <<"http://www.ejabberd.im/mod_webpresence">>}] + }, + #xmlel{ + name = <<"DESC">>, + attrs = [], + children = [{xmlcdata, <<"ejabberd web presence module\nCopyright (c) 2006-2007 Igor Goryachev, 2007 Badlop, 2014 runcom ">>}] + } + ]. get_wp(LUser, LServer) -> LUS = {LUser, LServer}, case catch mnesia:dirty_read(webpresence, LUS) of - {'EXIT', _Reason} -> + {'EXIT', _Reason} -> try_auto_webpresence(LUser, LServer); - [] -> + [] -> try_auto_webpresence(LUser, LServer); [WP] when is_record(WP, webpresence) -> WP end. try_auto_webpresence(LUser, LServer) -> - From = jlib:make_jid(LUser, LServer, ""), + From = jlib:make_jid(LUser, LServer, <<"">>), case acl:match_rule(LServer, ?AUTO_ACL, From) of - deny -> + deny -> #webpresence{}; - allow -> - #webpresence{us = {LUser, LServer}, - ridurl = false, - jidurl = true, - xml = true, - avatar = true, - js = true, - text = true, - icon = "jsf-jabber-text"} - end. - + allow -> + #webpresence{us = {LUser, LServer}, + ridurl = false, + jidurl = true, + xml = true, + avatar = true, + js = true, + text = true, + icon = <<"jsf-jabber-text">>} + end. get_status_weight(Show) -> case Show of - "chat" -> 0; - "available" -> 1; - "away" -> 2; - "xa" -> 3; - "dnd" -> 4; - _ -> 9 + <<"chat">> -> 0; + <<"available">> -> 1; + <<"away">> -> 2; + <<"xa">> -> 3; + <<"dnd">> -> 4; + _ -> 9 end. - session_to_presence(#session{sid = {_, Pid}, priority = Priority}) -> {_User, Resource, Show, Status} = ejabberd_c2s:get_presence(Pid), #presence{resource = Resource, @@ -546,6 +650,7 @@ session_to_presence(#session{sid = {_, Pid}, priority = Priority}) -> get_presences({bare, LUser, LServer}) -> [session_to_presence(Session) || Session <- mnesia:dirty_index_read(session, {LUser, LServer}, #session.us)]; + get_presences({sorted, LUser, LServer}) -> lists:sort( fun(A, B) -> @@ -559,112 +664,120 @@ get_presences({sorted, LUser, LServer}) -> end end, get_presences({bare, LUser, LServer})); + get_presences({xml, LUser, LServer, Show_us}) -> - {xmlelement, "presence", - case Show_us of - true -> [{"user", LUser}, {"server", LServer}]; - false -> [] - end, - lists:map( - fun(Presence) -> - {xmlelement, "resource", - [{"name", Presence#presence.resource}, - {"show", Presence#presence.show}, - {"priority", integer_to_list(Presence#presence.priority)}], - [{xmlcdata, Presence#presence.status}]} - end, - get_presences({sorted, LUser, LServer}))}; + #xmlel{ + name = <<"presence">>, + attrs = case Show_us of + true -> [{<<"user">>, LUser}, {<<"server">>, LServer}]; + false -> [] + end, + children = lists:map( + fun(Presence) -> + #xmlel{ + name = <<"resource">>, + attrs = [ + {<<"name">>, Presence#presence.resource}, + {<<"show">>, Presence#presence.show}, + {<<"priority">>, iolist_to_binary(integer_to_list(Presence#presence.priority))} + ], + children = [{xmlcdata, Presence#presence.status}] + } + end, + get_presences({sorted, LUser, LServer}) + ) + }; + get_presences({status, LUser, LServer, LResource}) -> case get_presences({sorted, LUser, LServer}) of - [] -> "unavailable"; - Rs -> + [] -> <<"unavailable">>; + Rs -> {value, R} = lists:keysearch(LResource, 2, Rs), - R#presence.status + R#presence.show %% TODO why was this "status"?! end; + get_presences({status, LUser, LServer}) -> case get_presences({sorted, LUser, LServer}) of [Highest | _Rest] -> - Highest#presence.status; + Highest#presence.show; %% TODO why was this "status"?! _ -> - "unavailable" + <<"unavailable">> end; + get_presences({show, LUser, LServer, LResource}) -> case get_presences({sorted, LUser, LServer}) of - [] -> "unavailable"; - Rs -> + [] -> <<"unavailable">>; + Rs -> {value, R} = lists:keysearch(LResource, 2, Rs), R#presence.show end; + get_presences({show, LUser, LServer}) -> case get_presences({sorted, LUser, LServer}) of [Highest | _Rest] -> Highest#presence.show; _ -> - "unavailable" + <<"unavailable">> end. make_js(WP, Prs, Show_us, Lang, Q) -> {User, Server} = WP#webpresence.us, BaseURL = get_baseurl(Server), US_string = case Show_us of - true -> - "var jabber_user='"++User++"';\n" - "var jabber_server='"++Server++"';\n"; - false -> "" + true -> + ?BC([<<"var jabber_user='">>, User, <<"';\n">>, <<"var jabber_server='">>, Server, <<"';\n">>]); false -> <<"">> end, FunImage = fun(I, S) -> case I of - "---" -> ""; - Icon -> " image:'"++BaseURL++"image/"++Icon++"/"++S++"'\n" + <<"---">> -> <<"">>; + Icon -> ?BC([<<" image:'">>, BaseURL, <<"image/">>, Icon, <<"/">>, S, <<"'\n">>]) end end, R_string_list = case Prs of - [] -> - Show = "unavailable", - ["{show:'"++Show++"',\n" - " long_show:'"++long_show(Show, Lang)++"',\n" - " status:'',\n" % TODO - ++ FunImage(WP#webpresence.icon, Show) ++ - "}"]; + [] -> + Show = <<"unavailable">>, + [?BC([<<"{show:'">>, Show, <<"',\n">>, + <<" long_show:'">>, long_show(Show, Lang), <<"',\n">>, + <<" status:'',\n">>, % TODO + FunImage(WP#webpresence.icon, Show), + <<"}">>])]; _ -> lists:map( fun(Pr) -> Show = Pr#presence.show, - "{name:'"++Pr#presence.resource++"',\n" - " priority:"++intund2string(Pr#presence.priority)++",\n" - " show:'"++Show++"',\n" - " long_show:'"++long_show(Show, Lang)++"',\n" - " status:'"++escape(Pr#presence.status)++"',\n" - ++ FunImage(WP#webpresence.icon, Show) ++ - "}" + ?BC([<<"{name:'">>, Pr#presence.resource, <<"',\n">>, + <<" priority:">>, intund2string(Pr#presence.priority), <<",\n">>, + <<" show:'">>, Show, <<"',\n">>, + <<" long_show:'">>, long_show(Show, Lang), <<"',\n">>, + <<" status:'">>, escape(Pr#presence.status), <<"',\n">>, + FunImage(WP#webpresence.icon, Show), + <<"}">>]) end, Prs) end, R_string = lists:foldl( fun(RS, Res) -> case Res of - "" -> RS; - _ -> Res ++ ",\n" ++ RS + <<"">> -> RS; + _ -> ?BC([Res, <<",\n">>, RS]) end end, - "", + <<"">>, R_string_list), - CB_string = case lists:keysearch("cb", 1, Q) of - {value, {_, CB}} -> " " ++ CB ++ "();"; - _ -> "" + CB_string = case lists:keysearch(<<"cb">>, 1, Q) of + {value, {_, CB}} -> ?BC([<<" ">>, CB, <<"();">>]); + _ -> <<"">> end, - US_string ++ "var jabber_resources=[\n"++R_string++"];" ++ CB_string. + ?BC([US_string, <<"var jabber_resources=[\n">>, R_string, <<"];">>, CB_string]). -long_show("available", Lang) -> ?T("available"); -long_show("chat", Lang) -> ?T("free for chat"); -long_show("away", Lang) -> ?T("away"); -long_show("xa", Lang) -> ?T("extended away"); -long_show("dnd", Lang) -> ?T("do not disturb"); -long_show(_, Lang) -> ?T("unavailable"). +long_show(<<"available">>, Lang) -> ?T(<<"available">>); +long_show(<<"chat">>, Lang) -> ?T(<<"free for chat">>); +long_show(<<"away">>, Lang) -> ?T(<<"away">>); +long_show(<<"xa">>, Lang) -> ?T(<<"extended away">>); +long_show(<<"dnd">>, Lang) -> ?T(<<"do not disturb">>); +long_show(_, Lang) -> ?T(<<"unavailable">>). -%% @spec(A) -> string() -%% where A = integer() | undefined -intund2string(undefined) -> "undefined"; -intund2string(Int) when is_integer(Int) -> integer_to_list(Int). +intund2string(undefined) -> <<"undefined">>; +intund2string(Int) when is_integer(Int) -> list_to_binary(integer_to_list(Int)). escape(S1) -> S2 = re:replace(S1, "\'", "\\'", [global, {return, list}]), @@ -673,11 +786,11 @@ escape(S1) -> get_baseurl(Host) -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), Proc ! {tell_baseurl, self()}, - receive + receive {baseurl_is, BaseURL} -> BaseURL end. --define(XML_HEADER, ""). +-define(XML_HEADER, <<"">>). get_pixmaps_directory() -> [{directory, Path} | _] = ets:lookup(pixmaps_dirs, directory), @@ -692,47 +805,57 @@ available_themes(list) -> {error, _} -> [] end; + available_themes(xdata) -> lists:map( fun(Theme) -> - {xmlelement, "option", [{"label", Theme}], - [{xmlelement, "value", [], [{xmlcdata, Theme}]}]} + #xmlel{ + name = <<"option">>, + attrs = [{<<"label">>, iolist_to_binary(Theme)}], + children = [ + #xmlel{ + name = <<"value">>, + attrs = [], + children = [{xmlcdata, iolist_to_binary(Theme)}] + } + ] + } end, available_themes(list)). show_presence({image_no_check, Theme, Pr}) -> Dir = get_pixmaps_directory(), - Image = Pr ++ ".{gif,png,jpg}", - [First | _Rest] = filelib:wildcard(filename:join([Dir, Theme, Image])), + Image = ?BC([Pr, <<".{gif,png,jpg}">>]), + [First | _Rest] = filelib:wildcard(binary_to_list(filename:join([Dir, Theme, Image]))), Mime = string:substr(First, string:len(First) - 2, 3), {ok, Content} = file:read_file(First), - {200, [{"Content-Type", "image/" ++ Mime}], binary_to_list(Content)}; + {200, [{<<"Content-Type">>, ?BC([<<"image/">>, ?BC(Mime)])}], binary_to_list(Content)}; show_presence({image, WP, LUser, LServer}) -> Icon = WP#webpresence.icon, - false = ("---" == Icon), + false = (<<"---">> == Icon), Pr = get_presences({show, LUser, LServer}), show_presence({image_no_check, Icon, Pr}); show_presence({image, WP, LUser, LServer, Theme}) -> - false = ("---" == WP#webpresence.icon), + false = (<<"---">> == WP#webpresence.icon), Pr = get_presences({show, LUser, LServer}), show_presence({image_no_check, Theme, Pr}); show_presence({image_res, WP, LUser, LServer, LResource}) -> Icon = WP#webpresence.icon, - false = ("---" == Icon), + false = (<<"---">> == Icon), Pr = get_presences({show, LUser, LServer, LResource}), show_presence({image_no_check, Icon, Pr}); show_presence({image_res, WP, LUser, LServer, Theme, LResource}) -> - false = ("---" == WP#webpresence.icon), + false = (<<"---">> == WP#webpresence.icon), Pr = get_presences({show, LUser, LServer, LResource}), show_presence({image_no_check, Theme, Pr}); show_presence({xml, WP, LUser, LServer, Show_us}) -> true = WP#webpresence.xml, - Presence_xml = xml:element_to_string(get_presences({xml, LUser, LServer, Show_us})), - {200, [{"Content-Type", "text/xml; charset=utf-8"}], ?XML_HEADER ++ Presence_xml}; + Presence_xml = xml:element_to_binary(get_presences({xml, LUser, LServer, Show_us})), + {200, [{"Content-Type", "text/xml; charset=utf-8"}], ?BC([?XML_HEADER, Presence_xml])}; show_presence({js, WP, LUser, LServer, Show_us, Lang, Q}) -> true = WP#webpresence.js, @@ -753,23 +876,22 @@ show_presence({text, WP, LUser, LServer, LResource}) -> show_presence({avatar, WP, LUser, LServer}) -> true = WP#webpresence.avatar, [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, LServer}), - JID = jlib:make_jid(LUser, LServer, ""), + JID = jlib:make_jid(LUser, LServer, <<"">>), IQ = #iq{type = get, xmlns = ?NS_VCARD}, IQr = Module:Function(JID, JID, IQ), [VCard] = IQr#iq.sub_el, - Mime = xml:get_path_s(VCard, [{elem, "PHOTO"}, {elem, "TYPE"}, cdata]), - BinVal = xml:get_path_s(VCard, [{elem, "PHOTO"}, {elem, "BINVAL"}, cdata]), + Mime = xml:get_path_s(VCard, [{elem, <<"PHOTO">>}, {elem, <<"TYPE">>}, cdata]), + BinVal = xml:get_path_s(VCard, [{elem, <<"PHOTO">>}, {elem, <<"BINVAL">>}, cdata]), Photo = jlib:decode_base64(BinVal), {200, [{"Content-Type", Mime}], Photo}; show_presence({image_example, Theme, Show}) -> Dir = get_pixmaps_directory(), - Image = Show ++ ".{gif,png,jpg}", - [First | _Rest] = filelib:wildcard(filename:join([Dir, Theme, Image])), + Image = ?BC([Show, <<".{gif,png,jpg}">>]), + [First | _Rest] = filelib:wildcard(binary_to_list(filename:join([Dir, Theme, Image]))), Mime = string:substr(First, string:len(First) - 2, 3), {ok, Content} = file:read_file(First), - {200, [{"Content-Type", "image/" ++ Mime}], binary_to_list(Content)}. - + {200, [{<<"Content-Type">>, ?BC([<<"image/">>, ?BC(Mime)])}], binary_to_list(Content)}. %% --------------------- %% Web Publish @@ -777,65 +899,86 @@ show_presence({image_example, Theme, Show}) -> make_xhtml(Els) -> make_xhtml([], Els). make_xhtml(Title, Els) -> - {xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}, - {"xml:lang", "en"}, - {"lang", "en"}], - [{xmlelement, "head", [], - [{xmlelement, "meta", [{"http-equiv", "Content-Type"}, - {"content", "text/html; charset=utf-8"}], []}] - ++ Title}, - {xmlelement, "body", [], Els} - ]}. + #xmlel{ + name = <<"html">>, + attrs = [ + {<<"xmlns">>, <<"http://www.w3.org/1999/xhtml">>}, + {<<"xml:lang">>, <<"en">>}, + {<<"lang">>, <<"en">>} + ], + children = [ + #xmlel{ + name = <<"head">>, + attrs = [], + children = [ + #xmlel{ + name = <<"meta">>, + attrs = [ + {<<"http-equiv">>, <<"Content-Type">>}, + {<<"content">>, <<"text/html; charset=utf-8">>} + ], + children = [] + } + ] ++ Title + }, + #xmlel{ + name = <<"body">>, + attrs = [], + children = Els + } + ] + }. themes_to_xhtml(Themes) -> ShowL = ["available", "chat", "dnd", "away", "xa", "unavailable"], THeadL = [""] ++ ShowL, - [?XAE("table", [], - [?XE("tr", [?XC("th", T) || T <- THeadL])] ++ - [?XE("tr", [?XC("td", Theme) | - [?XE("td", [?XA("img", [{"src", "image/"++Theme++"/"++T}])]) || T <- ShowL] + [?XAE(<<"table">>, [], + [?XE( <<"tr">>, [?XC(<<"th">>, ?BC(T)) || T <- THeadL])] ++ + [?XE(<<"tr">>, [?XC(<<"td">>, ?BC(Theme)) | + [?XE(<<"td">>, [?XA(<<"img">>, [{<<"src">>, ?BC([<<"image/">>, ?BC(Theme), <<"/">>, ?BC(T)]) }])]) || T <- ShowL] ] ) || Theme <- Themes] ) ]. -parse_lang(Lang) -> hd(string:tokens(Lang,"-")). +parse_lang(Lang) -> iolist_to_binary(hd(string:tokens(binary_to_list(Lang),"-"))). process(LocalPath, Request) -> case catch process2(LocalPath, Request) of {'EXIT', Reason} -> + ?DEBUG("~p", [Request]), ?DEBUG("The call to path ~p in the~nrequest: ~p~ncrashed with error: ~p", [LocalPath, Request, Reason]), - {404, [], make_xhtml([?XC("h1", "Not found")])}; + {404, [], make_xhtml([?XC(<<"h1">>, <<"Not found">>)])}; Res -> Res end. process2([], #request{lang = Lang1}) -> Lang = parse_lang(Lang1), - Title = [?XC("title", ?T("Web Presence"))], - Desc = [?XC("p", ?T("To publish your presence using this system you need a Jabber account in this Jabber server.")++" "++ - ?T("Login with a Jabber client, open the Service Discovery and register in Web Presence.")++ - ?T("You will receive a message with further instructions."))], - Link_themes = [?AC("themes", ?T("Icon Theme"))], - Body = [?XC("h1", ?T("Web Presence"))] ++ Desc ++ Link_themes, + Title = [?XC(<<"title">>, ?T(<<"Web Presence">>))], + Desc = [?XC(<<"p">>, ?BC([ ?T(<<"To publish your presence using this system you need a Jabber account in this Jabber server.">>), <<" ">>, + ?T(<<"Login with a Jabber client, open the Service Discovery and register in Web Presence.">>), + ?T(<<"You will receive a message with further instructions.">>)]))], + Link_themes = [?AC(<<"themes">>, ?T(<<"Icon Theme">>))], + Body = [?XC(<<"h1">>, ?T(<<"Web Presence">>))] ++ Desc ++ Link_themes, make_xhtml(Title, Body); -process2(["themes"], #request{lang = Lang1}) -> +process2([<<"themes">>], #request{lang = Lang1}) -> Lang = parse_lang(Lang1), - Title = [?XC("title", ?T("Web Presence")++" - "++?T("Icon Theme"))], + Title = [?XC(<<"title">>, ?BC([?T(<<"Web Presence">>), <<" - ">>, ?T("Icon Theme")]))], Themes = available_themes(list), Icon_themes = themes_to_xhtml(Themes), - Body = [?XC("h1", ?T("Icon Theme"))] ++ Icon_themes, + Body = [?XC(<<"h1">>, ?T(<<"Icon Theme">>))] ++ Icon_themes, make_xhtml(Title, Body); -process2(["image", Theme, Show], _Request) -> +process2([<<"image">>, Theme, Show], #request{} = _Request) -> Args = {image_example, Theme, Show}, show_presence(Args); -process2(["jid", User, Server | Tail], Request) -> +process2([<<"jid">>, User, Server | Tail], Request) -> serve_web_presence(jid, User, Server, Tail, Request); -process2(["rid", Rid | Tail], Request) -> +process2([<<"rid">>, Rid | Tail], Request) -> [Pr] = mnesia:dirty_index_read(webpresence, Rid, #webpresence.ridurl), {User, Server} = Pr#webpresence.us, serve_web_presence(rid, User, Server, Tail, Request); @@ -844,78 +987,77 @@ process2(["rid", Rid | Tail], Request) -> process2([User, Server | Tail], Request) -> serve_web_presence(jid, User, Server, Tail, Request). - serve_web_presence(TypeURL, User, Server, Tail, #request{lang = Lang1, q = Q}) -> LServer = jlib:nameprep(Server), - true = lists:member(LServer, ?MYHOSTS), + true = lists:member(Server, ?MYHOSTS), LUser = jlib:nodeprep(User), WP = get_wp(LUser, LServer), case TypeURL of jid -> true = WP#webpresence.jidurl; - rid -> true = is_list(WP#webpresence.ridurl) + rid -> true = is_binary(WP#webpresence.ridurl) end, Show_us = (TypeURL == jid), Lang = parse_lang(Lang1), Args = case Tail of - ["image", "theme", Theme, "res", Resource | _] -> - {image_res, WP, LUser, LServer, Theme, Resource}; - ["image", "theme", Theme | _] -> - {image, WP, LUser, LServer, Theme}; - ["image", "res", Resource | _] -> - {image_res, WP, LUser, LServer, Resource}; - ["image" | _] -> - {image, WP, LUser, LServer}; - ["xml"] -> - {xml, WP, LUser, LServer, Show_us}; - ["js"] -> - {js, WP, LUser, LServer, Show_us, Lang, Q}; - ["text"] -> - {text, WP, LUser, LServer}; - ["text", "res", Resource] -> - {text, WP, LUser, LServer, Resource}; - ["avatar" | _] -> - {avatar, WP, LUser, LServer} + [<<"image">>, <<"theme">>, Theme, <<"res">>, Resource | _] -> + {image_res, WP, LUser, LServer, Theme, Resource}; + [<<"image">>, <<"theme">>, Theme | _] -> + {image, WP, LUser, LServer, Theme}; + [<<"image">>, <<"res">>, Resource | _] -> + {image_res, WP, LUser, LServer, Resource}; + [<<"image">> | _] -> + {image, WP, LUser, LServer}; + [<<"xml">>] -> + {xml, WP, LUser, LServer, Show_us}; + [<<"js">>] -> + {js, WP, LUser, LServer, Show_us, Lang, Q}; + [<<"text">>] -> + {text, WP, LUser, LServer}; + [<<"text">>, <<"res">>, Resource] -> + {text, WP, LUser, LServer, Resource}; + [<<"avatar">> | _] -> + {avatar, WP, LUser, LServer} end, show_presence(Args). -%% --------------------- -%% Web Admin -%% --------------------- +%%%% --------------------- +%%%% Web Admin +%%%% --------------------- web_menu_host(Acc, _Host, Lang) -> - [{"webpresence", ?T("Web Presence")} | Acc]. + [{<<"webpresence">>, ?T(<<"Web Presence">>)} | Acc]. -web_page_host(_, _Host, - #request{path = ["webpresence"], +web_page_host(_, _Host, + #request{path = [<<"webpresence">>], lang = Lang} = _Request) -> - Res = [?XCT("h1", "Web Presence"), - ?XE("ul", [ - ?LI([?ACT("stats", "Statistics")]), - ?LI([?ACT("users", "Registered Users")])])], + Res = [?XCT(<<"h1">>, <<"Web Presence">>), + ?XE(<<"ul">>, [ + ?LI([?ACT(<<"stats">>, <<"Statistics">>)]), + ?LI([?ACT(<<"users">>, <<"Registered Users">>)])])], {stop, Res}; -web_page_host(_, Host, - #request{path = ["webpresence", "users"], +web_page_host(_, Host, + #request{path = [<<"webpresence">>, <<"users">>], lang = Lang} = _Request) -> Users = get_users(Host), Table = make_users_table(Users, Lang), - Res = [?XCT("h1", "Web Presence"), - ?XCT("h2", "Registered Users")] ++ Table, + Res = [?XCT(<<"h1">>, <<"Web Presence">>), + ?XCT(<<"h2">>, <<"Registered Users">>)] ++ Table, {stop, Res}; -web_page_host(_, Host, - #request{path = ["webpresence", "stats"], +web_page_host(_, Host, + #request{path = [<<"webpresence">>, <<"stats">>], lang = Lang} = _Request) -> Users = get_users(Host), - Res = [?XCT("h1", "Web Presence"), + Res = [?XCT(<<"h1">>, <<"Web Presence">>), css_table(), - ?XCT("h2", "Statistics")] + ?XCT(<<"h2">>, <<"Statistics">>)] ++ make_stats_options(Users, Lang) ++ make_stats_iconthemes(Users, Lang), {stop, Res}; -web_page_host(Acc, _, _) -> Acc. +web_page_host(Acc, _, _) -> Acc. get_users(Host) -> Select = [{{webpresence, {'$1', Host}, '$2', '$3', '$4', '$5', '$6', '$7', '$8'}, [], ['$$']}], @@ -924,29 +1066,29 @@ get_users(Host) -> make_users_table(Records, Lang) -> TList = lists:map( fun([User, RidUrl, JIDUrl, XML, Avatar, JS, Text, Icon]) -> - ?XE("tr", - [?XE("td", [?AC("../user/"++User++"/", User)]), - ?XC("td", atom_to_list(JIDUrl)), - ?XC("td", ridurl_out(RidUrl)), - ?XC("td", Icon), - ?XC("td", atom_to_list(XML)), - ?XC("td", atom_to_list(JS)), - ?XC("td", atom_to_list(Text)), - ?XC("td", atom_to_list(Avatar))]) + ?XE(<<"tr">>, + [?XE(<<"td">>, [?AC(?BC([<<"../user/">>, User, <<"/">>]), User)]), + ?XC(<<"td">>, iolist_to_binary(atom_to_list(JIDUrl))), + ?XC(<<"td">>, ridurl_out(RidUrl)), + ?XC(<<"td">>, Icon), + ?XC(<<"td">>, iolist_to_binary(atom_to_list(XML))), + ?XC(<<"td">>, iolist_to_binary(atom_to_list(JS))), + ?XC(<<"td">>, iolist_to_binary(atom_to_list(Text))), + ?XC(<<"td">>, iolist_to_binary(atom_to_list(Avatar)))]) end, Records), - [?XE("table", - [?XE("thead", - [?XE("tr", - [?XCT("td", "User"), - ?XCT("td", "Jabber ID"), - ?XCT("td", "Random ID"), - ?XCT("td", "Icon Theme"), - ?XC("td", "XML"), - ?XC("td", "JS"), - ?XCT("td", "Text"), - ?XCT("td", "Avatar") + [?XE(<<"table">>, + [?XE(<<"thead">>, + [?XE(<<"tr">>, + [?XCT(<<"td">>, <<"User">>), + ?XCT(<<"td">>, <<"Jabber ID">>), + ?XCT(<<"td">>, <<"Random ID">>), + ?XCT(<<"td">>, <<"Icon Theme">>), + ?XC(<<"td">>, <<"XML">>), + ?XC(<<"td">>, <<"JS">>), + ?XCT(<<"td">>, <<"Text">>), + ?XCT(<<"td">>, <<"Avatar">>) ])]), - ?XE("tbody", TList)])]. + ?XE(<<"tbody">>, TList)])]. make_stats_options(Records, Lang) -> [RegUsers, JJ, RR, XX, AA, SS, TT, II] = lists:foldl( @@ -957,22 +1099,22 @@ make_stats_options(Records, Lang) -> A2 = A + case Avatar of false -> 0; true -> 1 end, S2 = S + case JS of false -> 0; true -> 1 end, T2 = T + case Text of false -> 0; true -> 1 end, - I2 = I + case Icon of "---" -> 0; _ -> 1 end, + I2 = I + case Icon of <<"---">> -> 0; _ -> 1 end, [N+1, J2, R2, X2, A2, S2, T2, I2] - end, + end, [0, 0, 0, 0, 0, 0, 0, 0], Records), - URLTList = [{"Jabber ID", JJ}, {"Random ID", RR}], - OutputTList = [{"Icon Theme", II}, {"XML", XX}, {"JavaScript", SS}, {"Text", TT}, {"Avatar", AA}], + URLTList = [{<<"Jabber ID">>, JJ}, {<<"Random ID">>, RR}], + OutputTList = [{<<"Icon Theme">>, II}, {<<"XML">>, XX}, {<<"JavaScript">>, SS}, {<<"Text">>, TT}, {<<"Avatar">>, AA}], [ - ?C("Registered Users" ++": "++ integer_to_list(RegUsers)), - ?XCT("h3", "URL Type"), - ?XAE("table", [{"class", "stats"}], - [?XE("tbody", do_stat_table_with(URLTList, RegUsers))] + ?C(?BC([<<"Registered Users">>, <<": ">>, iolist_to_binary(integer_to_list(RegUsers))])), + ?XCT(<<"h3">>, <<"URL Type">>), + ?XAE(<<"table">>, [{<<"class">>, <<"stats">>}], + [?XE(<<"tbody">>, do_stat_table_with(URLTList, RegUsers))] ), - ?XCT("h3", "Output Type"), - ?XAE("table", [{"class", "stats"}], - [?XE("tbody", do_stat_table_with(OutputTList, RegUsers))] + ?XCT(<<"h3">>, <<"Output Type">>), + ?XAE(<<"table">>, [{<<"class">>, <<"stats">>}], + [?XE(<<"tbody">>, do_stat_table_with(OutputTList, RegUsers))] )]. make_stats_iconthemes(Records, Lang) -> @@ -980,13 +1122,13 @@ make_stats_iconthemes(Records, Lang) -> Dict = lists:foldl( fun([_, _, _, _, _, _, _, Icon], D) -> dict:update_counter(Icon, 1, D) - end, + end, dict:from_list(Themes1), Records), Themes = lists:keysort(1, dict:to_list(Dict)), - [?XCT("h3", "Icon Theme"), - ?XAE("table", [{"class", "stats"}], - [?XE("tbody", do_stat_table_with(Themes))] + [?XCT(<<"h3">>, <<"Icon Theme">>), + ?XAE(<<"table">>, [{<<"class">>, <<"stats">>}], + [?XE(<<"tbody">>, do_stat_table_with(Themes))] )]. %% Do table with bars @@ -997,32 +1139,33 @@ do_stat_table_with(Values) -> do_stat_table_with(Values, Total) -> lists:map( - fun({L, N}) -> + fun({L, N}) -> Perc = case Total of - 0 -> "0"; - _ -> integer_to_list(trunc(100 * N / Total)) + 0 -> <<"0">>; + _ -> iolist_to_binary(integer_to_list(trunc(100 * N / Total))) end, do_table_element(?C(L), io_lib:format("~p", [N]), Perc) end, Values). do_table_element(L, [N], Perc) -> - ?XE("tr", - [?XE("td", [L]), - ?XAC("td", [{"class", "alignright"}], [N]), - ?XE("td", - [?XAE("div", - [{"class", "graph"}], - [?XAC("div", - [{"class", "bar"}, {"style", "width: " ++ Perc ++ "%;"}], + ?XE(<<"tr">>, + [?XE(<<"td">>, [L]), + ?XAC(<<"td">>, [{<<"class">>, <<"alignright">>}], [N]), + ?XE(<<"td">>, + [?XAE(<<"div">>, + [{<<"class">>, <<"graph">>}], + [?XAC(<<"div">>, + [{<<"class">>, <<"bar">>}, {<<"style">>, ?BC([<<"width: ">>, Perc, <<"%;">>])}], [] )] )] ), - ?XAC("td", [{"class", "alignright"}], [Perc++"%"]) + ?XAC(<<"td">>, [{<<"class">>, <<"alignright">>}], [?BC([Perc, <<"%">>])]) ]). + css_table()-> - ?XAE("style", [{"type", "text/css"}], - [?C(".stats { + ?XAE(<<"style">>, [{<<"type">>, <<"text/css">>}], + [?C(<<".stats { padding-left: 20px; padding-top: 10px; } @@ -1041,7 +1184,7 @@ css_table()-> height: 1.5em; line-height: 1.5em; } - .graph .bar span { position: absolute; left: 1em; }")]). + .graph .bar span { position: absolute; left: 1em; }">>)]). %%%-------------------------------- From 3f68bb65b9dcaa35550301960a4b4d67c1dbaefc Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Wed, 9 Apr 2014 23:12:53 +0200 Subject: [PATCH 11/13] mod_s2s_log: Remove ?DEBUG() calls Current ejabberd versions support two different logging frameworks that require different build options. There's currently no easy way to deal with this for external modules, so let's omit the ?DEBUG() calls for the moment. --- mod_s2s_log/src/mod_s2s_log.erl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mod_s2s_log/src/mod_s2s_log.erl b/mod_s2s_log/src/mod_s2s_log.erl index de403d2..4d821d9 100644 --- a/mod_s2s_log/src/mod_s2s_log.erl +++ b/mod_s2s_log/src/mod_s2s_log.erl @@ -50,12 +50,11 @@ -record(config, {filename=?DEFAULT_FILENAME, iodevice}). %% For now we only support one log file for all vhosts. -start(Host, Opts) -> +start(_Host, Opts) -> %% ejabberd starts modules sequentially so we assume no race %% condition is possible here case whereis(?PROCNAME) of undefined -> - ?DEBUG("Starting mod_s2s_log ~p ~p~n", [Host, Opts]), Filename = gen_mod:get_opt(filename, Opts, ?DEFAULT_FILENAME), %% TODO: Both hooks will need Host parameter for vhost support ejabberd_hooks:add(reopen_log_hook, ?MODULE, reopen_log, 55), @@ -67,7 +66,6 @@ start(Host, Opts) -> end. init(Config)-> - ?DEBUG("Starting mod_s2s_log ~p with config ~p~n", [?MODULE, Config]), {ok, IOD} = file:open(Config#config.filename, ?FILE_OPTS), loop(Config#config{iodevice=IOD}). @@ -79,7 +77,6 @@ loop(Config) -> {reopen_log} -> file:close(Config#config.iodevice), {ok, IOD} = file:open(Config#config.filename, ?FILE_OPTS), - ?INFO_MSG("Reopened s2s log file", []), loop(Config#config{iodevice = IOD}); stop -> file:close(Config#config.iodevice), From 3ba48bac80e9840f21eae2b5ff619a3245ebd24d Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Wed, 9 Apr 2014 23:14:33 +0200 Subject: [PATCH 12/13] mod_s2s_log: Update gen_mod:get_opt() call Adjust the gen_mod:get_opt() call to work with current ejabberd versions. --- mod_s2s_log/src/mod_s2s_log.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod_s2s_log/src/mod_s2s_log.erl b/mod_s2s_log/src/mod_s2s_log.erl index 4d821d9..2dae0a0 100644 --- a/mod_s2s_log/src/mod_s2s_log.erl +++ b/mod_s2s_log/src/mod_s2s_log.erl @@ -44,7 +44,7 @@ -include("ejabberd.hrl"). -define(PROCNAME, ?MODULE). --define(DEFAULT_FILENAME, "s2s.log"). +-define(DEFAULT_FILENAME, <<"s2s.log">>). -define(FILE_OPTS, [append,raw]). -record(config, {filename=?DEFAULT_FILENAME, iodevice}). @@ -55,7 +55,7 @@ start(_Host, Opts) -> %% condition is possible here case whereis(?PROCNAME) of undefined -> - Filename = gen_mod:get_opt(filename, Opts, ?DEFAULT_FILENAME), + Filename = gen_mod:get_opt(filename, Opts, fun(V) -> V end, ?DEFAULT_FILENAME), %% TODO: Both hooks will need Host parameter for vhost support ejabberd_hooks:add(reopen_log_hook, ?MODULE, reopen_log, 55), ejabberd_hooks:add(s2s_connect_hook, ?MODULE, s2s_connect, 55), From 33dfbf1ef69a1b18d14d7517904494a5d1673498 Mon Sep 17 00:00:00 2001 From: Holger Weiss Date: Wed, 9 Apr 2014 23:30:03 +0200 Subject: [PATCH 13/13] mod_muc_admin: Fix "muc_online_rooms" output Don't split the components of room JIDs in the "muc_online_rooms" output. --- mod_muc_admin/src/mod_muc_admin.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod_muc_admin/src/mod_muc_admin.erl b/mod_muc_admin/src/mod_muc_admin.erl index bf05c81..fd7982d 100644 --- a/mod_muc_admin/src/mod_muc_admin.erl +++ b/mod_muc_admin/src/mod_muc_admin.erl @@ -171,9 +171,9 @@ muc_online_rooms(ServerHost) -> fun({_, {Roomname, Host}, _}, Results) -> case MUCHost of global -> - [Roomname, <<"@">>, Host | Results]; + [<> | Results]; Host -> - [Roomname, <<"@">>, Host | Results]; + [<> | Results]; _ -> Results end