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 0000000..ab57011 Binary files /dev/null and b/mod_webpresence/data/pixmaps/simple/available.png differ diff --git a/mod_webpresence/data/pixmaps/simple/away.png b/mod_webpresence/data/pixmaps/simple/away.png new file mode 100644 index 0000000..0d148f3 Binary files /dev/null and b/mod_webpresence/data/pixmaps/simple/away.png differ diff --git a/mod_webpresence/data/pixmaps/simple/chat.png b/mod_webpresence/data/pixmaps/simple/chat.png new file mode 100644 index 0000000..d6fb64c Binary files /dev/null and b/mod_webpresence/data/pixmaps/simple/chat.png differ diff --git a/mod_webpresence/data/pixmaps/simple/dnd.png b/mod_webpresence/data/pixmaps/simple/dnd.png new file mode 100644 index 0000000..d2bca6c Binary files /dev/null and b/mod_webpresence/data/pixmaps/simple/dnd.png differ diff --git a/mod_webpresence/data/pixmaps/simple/unavailable.png b/mod_webpresence/data/pixmaps/simple/unavailable.png new file mode 100644 index 0000000..e9186fa Binary files /dev/null and b/mod_webpresence/data/pixmaps/simple/unavailable.png differ diff --git a/mod_webpresence/data/pixmaps/simple/xa.png b/mod_webpresence/data/pixmaps/simple/xa.png new file mode 100644 index 0000000..3b65868 Binary files /dev/null and b/mod_webpresence/data/pixmaps/simple/xa.png differ 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; }">>)]). %%%--------------------------------