2013-04-15 12:03:14 +02:00
|
|
|
%%%----------------------------------------------------------------------
|
|
|
|
%%% File : mod_webpresence.erl
|
2014-04-08 00:10:05 +02:00
|
|
|
%%% Author : Igor Goryachev <igor@goryachev.org>, Badlop, runcom <antonio.murdaca@gmail.com>
|
2013-04-15 12:03:14 +02:00
|
|
|
%%% Purpose : Allow user to show presence in the web
|
|
|
|
%%% Created : 30 Apr 2006 by Igor Goryachev <igor@goryachev.org>
|
|
|
|
%%% Id : $Id: mod_webpresence.erl 1083 2010-06-01 18:32:55Z badlop $
|
|
|
|
%%%----------------------------------------------------------------------
|
|
|
|
|
|
|
|
-module(mod_webpresence).
|
|
|
|
|
|
|
|
-behaviour(gen_server).
|
|
|
|
-behaviour(gen_mod).
|
|
|
|
|
|
|
|
%% API
|
|
|
|
-export([start_link/2,
|
|
|
|
start/2,
|
|
|
|
stop/1,
|
|
|
|
remove_user/2,
|
|
|
|
web_menu_host/3, web_page_host/3,
|
2014-04-08 00:10:05 +02:00
|
|
|
process/2
|
|
|
|
]).
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
%% gen_server callbacks
|
|
|
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
|
|
|
terminate/2, code_change/3]).
|
|
|
|
|
|
|
|
-include("ejabberd.hrl").
|
|
|
|
-include("jlib.hrl").
|
2014-04-08 00:10:05 +02:00
|
|
|
-include("logger.hrl").
|
|
|
|
-include("ejabberd_web_admin.hrl").
|
|
|
|
-include("ejabberd_http.hrl").
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
-record(webpresence, {us, ridurl = false, jidurl = false, xml = false, avatar = false, js = false, text = false, icon = "---"}).
|
|
|
|
-record(state, {host, server_host, base_url, access}).
|
|
|
|
-record(presence, {resource, show, priority, status}).
|
|
|
|
|
|
|
|
%% Copied from ejabberd_sm.erl
|
|
|
|
-record(session, {sid, usr, us, priority, info}).
|
|
|
|
|
|
|
|
-define(PROCNAME, ejabberd_mod_webpresence).
|
2014-04-08 00:10:05 +02:00
|
|
|
-define(PIXMAPS_DIR, <<"pixmaps">>).
|
2013-04-15 12:03:14 +02:00
|
|
|
-define(AUTO_ACL, webpresence_auto).
|
|
|
|
|
|
|
|
|
|
|
|
%%====================================================================
|
|
|
|
%% API
|
|
|
|
%%====================================================================
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
|
|
|
|
%% Description: Starts the server
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
start_link(Host, Opts) ->
|
|
|
|
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
|
|
|
gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []).
|
|
|
|
|
|
|
|
start(Host, Opts) ->
|
|
|
|
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
2014-04-08 00:10:05 +02:00
|
|
|
ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]},
|
|
|
|
temporary, 1000, worker, [?MODULE]},
|
2013-04-15 12:03:14 +02:00
|
|
|
Default_dir = case code:priv_dir(ejabberd) of
|
|
|
|
{error, _} -> ?PIXMAPS_DIR;
|
|
|
|
Path -> filename:join([Path, ?PIXMAPS_DIR])
|
|
|
|
end,
|
2014-04-08 00:10:05 +02:00
|
|
|
Dir = gen_mod:get_opt(pixmaps_path, Opts, fun(D) -> D end, Default_dir),
|
2013-04-15 12:03:14 +02:00
|
|
|
catch ets:new(pixmaps_dirs, [named_table, public]),
|
|
|
|
ets:insert(pixmaps_dirs, {directory, Dir}),
|
|
|
|
supervisor:start_child(ejabberd_sup, ChildSpec).
|
|
|
|
|
|
|
|
stop(Host) ->
|
|
|
|
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
|
|
|
gen_server:call(Proc, stop),
|
|
|
|
supervisor:terminate_child(ejabberd_sup, Proc),
|
|
|
|
supervisor:delete_child(ejabberd_sup, Proc).
|
|
|
|
|
|
|
|
%%====================================================================
|
|
|
|
%% gen_server callbacks
|
|
|
|
%%====================================================================
|
|
|
|
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
%% Function: init(Args) -> {ok, State} |
|
|
|
|
%% {ok, State, Timeout} |
|
|
|
|
%% ignore |
|
|
|
|
%% {stop, Reason}
|
|
|
|
%% Description: Initiates the server
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
init([Host, Opts]) ->
|
|
|
|
mnesia:create_table(webpresence,
|
|
|
|
[{disc_copies, [node()]},
|
|
|
|
{attributes, record_info(fields, webpresence)}]),
|
|
|
|
mnesia:add_table_index(webpresence, ridurl),
|
|
|
|
update_table(),
|
2014-04-08 00:10:05 +02:00
|
|
|
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">>),
|
2014-09-14 22:45:05 +02:00
|
|
|
BaseURL1 = gen_mod:get_opt(baseurl, Opts, fun(O) -> O end,
|
|
|
|
iolist_to_binary(io_lib:format(<<"http://~s:~p/~s/">>, [Host, Port, Path]))),
|
|
|
|
BaseURL2 = ejabberd_regexp:greplace(BaseURL1, <<"@HOST@">>, Host),
|
2013-04-15 12:03:14 +02:00
|
|
|
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),
|
|
|
|
ejabberd_hooks:add(webadmin_page_host, Host, ?MODULE, web_page_host, 50),
|
|
|
|
{ok, #state{host = MyHost,
|
|
|
|
server_host = Host,
|
2014-09-14 22:45:05 +02:00
|
|
|
base_url = BaseURL2,
|
2013-04-15 12:03:14 +02:00
|
|
|
access = Access}}.
|
|
|
|
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
|
|
|
|
%% {reply, Reply, State, Timeout} |
|
|
|
|
%% {noreply, State} |
|
|
|
|
%% {noreply, State, Timeout} |
|
|
|
|
%% {stop, Reason, Reply, State} |
|
|
|
|
%% {stop, Reason, State}
|
|
|
|
%% Description: Handling call messages
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
handle_call(stop, _From, State) ->
|
|
|
|
{stop, normal, ok, State}.
|
|
|
|
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
%% Function: handle_cast(Msg, State) -> {noreply, State} |
|
|
|
|
%% {noreply, State, Timeout} |
|
|
|
|
%% {stop, Reason, State}
|
|
|
|
%% Description: Handling cast messages
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
handle_cast(_Msg, State) ->
|
|
|
|
{noreply, State}.
|
|
|
|
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
%% Function: handle_info(Info, State) -> {noreply, State} |
|
|
|
|
%% {noreply, State, Timeout} |
|
|
|
|
%% {stop, Reason, State}
|
|
|
|
%% Description: Handling all non call/cast messages
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
handle_info({route, From, To, Packet},
|
|
|
|
#state{host = Host,
|
|
|
|
server_host = ServerHost,
|
|
|
|
base_url = BaseURL,
|
|
|
|
access = Access} = State) ->
|
|
|
|
case catch do_route(Host, ServerHost, Access, From, To, Packet, BaseURL) of
|
|
|
|
{'EXIT', Reason} ->
|
|
|
|
?ERROR_MSG("~p", [Reason]);
|
|
|
|
_ ->
|
|
|
|
ok
|
|
|
|
end,
|
|
|
|
{noreply, State};
|
|
|
|
|
|
|
|
|
|
|
|
handle_info({tell_baseurl, Pid},
|
|
|
|
#state{base_url = BaseURL} = State) ->
|
|
|
|
Pid ! {baseurl_is, BaseURL},
|
|
|
|
{noreply, State};
|
|
|
|
|
|
|
|
handle_info(_Info, State) ->
|
|
|
|
{noreply, State}.
|
|
|
|
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
%% Function: terminate(Reason, State) -> void()
|
|
|
|
%% Description: This function is called by a gen_server when it is about to
|
|
|
|
%% terminate. It should be the opposite of Module:init/1 and do any necessary
|
|
|
|
%% cleaning up. When it returns, the gen_server terminates with Reason.
|
|
|
|
%% The return value is ignored.
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
terminate(_Reason, #state{host = Host}) ->
|
|
|
|
ejabberd_router:unregister_route(Host),
|
|
|
|
ejabberd_hooks:delete(remove_user, Host, ?MODULE, remove_user, 50),
|
|
|
|
ejabberd_hooks:delete(webadmin_menu_host, Host, ?MODULE, web_menu_host, 50),
|
|
|
|
ejabberd_hooks:delete(webadmin_page_host, Host, ?MODULE, web_page_host, 50),
|
|
|
|
ok.
|
|
|
|
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
|
|
|
|
%% Description: Convert process state when code is changed
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
code_change(_OldVsn, State, _Extra) ->
|
|
|
|
{ok, State}.
|
|
|
|
|
|
|
|
%%--------------------------------------------------------------------
|
|
|
|
%%% 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);
|
|
|
|
_ ->
|
2014-04-08 00:10:05 +02:00
|
|
|
#xmlel{attrs = Attrs} = Packet,
|
|
|
|
Lang = xml:get_attr_s(<<"xml:lang">>, Attrs),
|
|
|
|
ErrText = <<"Access denied by service policy">>,
|
2013-04-15 12:03:14 +02:00
|
|
|
Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, ErrText)),
|
|
|
|
ejabberd_router:route(To, From, Err)
|
|
|
|
end.
|
|
|
|
|
|
|
|
do_route1(Host, From, To, Packet, BaseURL) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
#xmlel{name = Name, attrs = Attrs} = Packet,
|
2013-04-15 12:03:14 +02:00
|
|
|
case Name of
|
2014-04-08 00:10:05 +02:00
|
|
|
<<"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;
|
2013-04-15 12:03:14 +02:00
|
|
|
_ -> Err = jlib:make_error_reply(Packet, ?ERR_ITEM_NOT_FOUND),
|
|
|
|
ejabberd_router:route(To, From, Err)
|
|
|
|
end
|
|
|
|
end.
|
|
|
|
|
|
|
|
do_route1_iq(_, From, To, _, _,
|
|
|
|
#iq{type = get, xmlns = ?NS_DISCO_INFO, lang = Lang} = IQ) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
SubEl = #xmlel{
|
|
|
|
name = <<"query">>,
|
|
|
|
attrs = [{<<"xmlns">>, ?NS_DISCO_INFO}],
|
|
|
|
children = iq_disco_info(Lang)
|
|
|
|
},
|
|
|
|
Res = IQ#iq{type = result, sub_el = [SubEl]},
|
2013-04-15 12:03:14 +02:00
|
|
|
ejabberd_router:route(To, From, jlib:iq_to_xml(Res));
|
|
|
|
|
|
|
|
do_route1_iq(_, _, _, _, _,
|
|
|
|
#iq{type = get, xmlns = ?NS_DISCO_ITEMS}) ->
|
|
|
|
ok;
|
|
|
|
|
|
|
|
do_route1_iq(Host, From, To, _, _,
|
|
|
|
#iq{type = get, xmlns = ?NS_REGISTER, lang = Lang} = IQ) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
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]},
|
2013-04-15 12:03:14 +02:00
|
|
|
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} ->
|
2014-04-08 00:10:05 +02:00
|
|
|
SubEl2 = #xmlel{
|
|
|
|
name = <<"query">>,
|
|
|
|
attrs = [{<<"xmlns">>, ?NS_REGISTER}],
|
|
|
|
children = IQRes
|
|
|
|
},
|
2013-04-15 12:03:14 +02:00
|
|
|
Res = IQ#iq{type = result, sub_el = [SubEl2]},
|
|
|
|
ejabberd_router:route(To, From, jlib:iq_to_xml(Res));
|
|
|
|
{error, Error} ->
|
|
|
|
Err = jlib:make_error_reply(Packet, Error),
|
|
|
|
ejabberd_router:route(To, From, Err)
|
|
|
|
end;
|
|
|
|
|
|
|
|
do_route1_iq(_Host, From, To, _, _,
|
|
|
|
#iq{type = get, xmlns = ?NS_VCARD = XMLNS} = IQ) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
SubEl = #xmlel{
|
|
|
|
name = <<"vCard">>,
|
|
|
|
attrs = [{<<"xmlns">>, XMLNS}],
|
|
|
|
children = iq_get_vcard()
|
|
|
|
},
|
|
|
|
Res = IQ#iq{type = result, sub_el = [SubEl]},
|
2013-04-15 12:03:14 +02:00
|
|
|
ejabberd_router:route(To, From, jlib:iq_to_xml(Res));
|
|
|
|
|
|
|
|
do_route1_iq(_Host, From, To, Packet, _, #iq{}) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
Err = jlib:make_error_reply(Packet, ?ERR_FEATURE_NOT_IMPLEMENTED),
|
2013-04-15 12:03:14 +02:00
|
|
|
ejabberd_router:route(To, From, Err);
|
|
|
|
|
|
|
|
do_route1_iq(_, _, _, _, _, _) ->
|
|
|
|
ok.
|
|
|
|
|
|
|
|
iq_disco_info(Lang) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
[#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 = []
|
|
|
|
}].
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
-define(XFIELDS(Type, Label, Var, Vals),
|
2014-04-08 00:10:05 +02:00
|
|
|
#xmlel{
|
|
|
|
name = <<"field">>,
|
|
|
|
attrs = [
|
|
|
|
{<<"type">>, Type},
|
|
|
|
{<<"label">>, ?T(Label)},
|
|
|
|
{<<"var">>, Var}
|
|
|
|
],
|
|
|
|
children = Vals
|
|
|
|
}).
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
-define(XFIELD(Type, Label, Var, Val),
|
2014-04-08 00:10:05 +02:00
|
|
|
?XFIELDS(Type, Label, Var,
|
|
|
|
[
|
|
|
|
#xmlel{
|
|
|
|
name = <<"value">>,
|
|
|
|
attrs = [],
|
|
|
|
children = [{xmlcdata, Val}]
|
|
|
|
}])
|
2013-04-15 12:03:14 +02:00
|
|
|
).
|
|
|
|
|
|
|
|
-define(XFIELDFIXED(Val),
|
2014-04-08 00:10:05 +02:00
|
|
|
#xmlel{
|
|
|
|
name = <<"field">>,
|
|
|
|
attrs = [{<<"type">>, <<"fixed">>}],
|
|
|
|
children = [
|
|
|
|
#xmlel{
|
|
|
|
name = <<"value">>,
|
|
|
|
attrs = [],
|
|
|
|
children = [{xmlcdata, Val}]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
2013-04-15 12:03:14 +02:00
|
|
|
).
|
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
-define(ATOM2BINARY(Val), iolist_to_binary(atom_to_list(Val))).
|
|
|
|
-define(BC(L), iolist_to_binary(L)).
|
|
|
|
|
|
|
|
ridurl_out(false) -> <<"false">>;
|
|
|
|
ridurl_out(Id) when is_binary(Id) -> <<"true">>.
|
2013-04-15 12:03:14 +02:00
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
to_bool(<<"false">>) -> false;
|
|
|
|
to_bool(<<"true">>) -> true;
|
|
|
|
to_bool(<<"0">>) -> false;
|
|
|
|
to_bool(<<"1">>) -> true.
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
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};
|
|
|
|
_ ->
|
2014-04-08 00:10:05 +02:00
|
|
|
{true, false, false, false, false, false, <<"---">>, false}
|
2013-04-15 12:03:14 +02:00
|
|
|
end.
|
|
|
|
|
|
|
|
get_pr_rid(LUS) ->
|
|
|
|
{_, H, _, _, _, _, _, _} = get_pr(LUS),
|
|
|
|
H.
|
|
|
|
|
|
|
|
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),
|
2014-04-08 00:10:05 +02:00
|
|
|
RegisteredXML = case Registered of
|
|
|
|
true -> [#xmlel{name = <<"registered">>, attrs = [], children = []}];
|
2013-04-15 12:03:14 +02:00
|
|
|
false -> []
|
|
|
|
end,
|
|
|
|
RegisteredXML ++
|
2014-04-08 00:10:05 +02:00
|
|
|
[
|
|
|
|
#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
|
2013-04-15 12:03:14 +02:00
|
|
|
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),
|
2014-04-08 00:10:05 +02:00
|
|
|
Check_OutputTypes = (XML == true) or (Avatar == true) or (JS == true) or (Text == true) or (Icon =/= <<"---">>),
|
2013-04-15 12:03:14 +02:00
|
|
|
case Check_URLTypes and Check_OutputTypes of
|
|
|
|
true -> iq_set_register_info2(From, LUS, Opts);
|
|
|
|
false -> unregister_webpresence(From, Host, Lang)
|
|
|
|
end.
|
|
|
|
|
|
|
|
iq_set_register_info2(From, LUS, {Host, JidUrl, RidUrl, XML, Avatar, JS, Text, Icon, BaseURL, Lang}) ->
|
|
|
|
RidUrl2 = get_rid_final_value(RidUrl, LUS),
|
|
|
|
WP = #webpresence{us = LUS,
|
|
|
|
jidurl = JidUrl,
|
|
|
|
ridurl = RidUrl2,
|
|
|
|
xml = XML,
|
|
|
|
avatar = Avatar,
|
|
|
|
js = JS,
|
|
|
|
text = Text,
|
|
|
|
icon = Icon},
|
|
|
|
F = fun() -> mnesia:write(WP) end,
|
|
|
|
case mnesia:transaction(F) of
|
|
|
|
{atomic, ok} ->
|
|
|
|
send_message_registered(WP, From, Host, BaseURL, Lang),
|
|
|
|
{result, []};
|
|
|
|
_ ->
|
|
|
|
{error, ?ERR_INTERNAL_SERVER_ERROR}
|
|
|
|
end.
|
|
|
|
|
|
|
|
get_rid_final_value(false, _) -> false;
|
|
|
|
get_rid_final_value(true, {U, S} = LUS) ->
|
|
|
|
case get_pr_rid(LUS) of
|
|
|
|
false ->
|
2014-04-08 00:10:05 +02:00
|
|
|
iolist_to_binary(integer_to_list(erlang:phash2(U) * erlang:phash2(S)
|
2013-04-15 12:03:14 +02:00
|
|
|
* calendar:datetime_to_gregorian_seconds(
|
2014-04-08 00:10:05 +02:00
|
|
|
calendar:local_time()))
|
|
|
|
++ randoms:get_string());
|
|
|
|
H when is_binary(H) ->
|
2013-04-15 12:03:14 +02:00
|
|
|
H
|
|
|
|
end.
|
|
|
|
|
|
|
|
send_message_registered(WP, To, Host, BaseURL, Lang) ->
|
|
|
|
{User, Server} = WP#webpresence.us,
|
2014-04-08 00:10:05 +02:00
|
|
|
JID = jlib:make_jid(User, Server, <<"">>),
|
2013-04-15 12:03:14 +02:00
|
|
|
JIDS = jlib:jid_to_string(JID),
|
|
|
|
Oavatar = case WP#webpresence.avatar of
|
2014-04-08 00:10:05 +02:00
|
|
|
false -> <<"">>;
|
|
|
|
true -> <<" avatar\n"
|
|
|
|
" avatar/my.png\n">>
|
2013-04-15 12:03:14 +02:00
|
|
|
end,
|
|
|
|
Ojs = case WP#webpresence.js of
|
2014-04-08 00:10:05 +02:00
|
|
|
false -> <<"">>;
|
|
|
|
true -> <<" js\n">>
|
2013-04-15 12:03:14 +02:00
|
|
|
end,
|
|
|
|
Otext = case WP#webpresence.text of
|
2014-04-08 00:10:05 +02:00
|
|
|
false -> <<"">>;
|
|
|
|
true -> ?BC([
|
|
|
|
<<" text\n"
|
|
|
|
" text/res/<">>, ?T(<<"Resource">>), <<">\n">>
|
|
|
|
])
|
2013-04-15 12:03:14 +02:00
|
|
|
end,
|
|
|
|
Oimage = case WP#webpresence.icon of
|
2014-04-08 00:10:05 +02:00
|
|
|
<<"---">> -> "";
|
|
|
|
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">>
|
|
|
|
])
|
2013-04-15 12:03:14 +02:00
|
|
|
end,
|
|
|
|
Oxml = case WP#webpresence.xml of
|
2014-04-08 00:10:05 +02:00
|
|
|
false -> <<"">>;
|
|
|
|
true -> <<" xml\n">>
|
2013-04-15 12:03:14 +02:00
|
|
|
end,
|
|
|
|
Allowed_type = case {Oimage, Oxml, Oavatar, Otext, Ojs} of
|
2014-04-08 00:10:05 +02:00
|
|
|
{<<"">>, <<"">>, <<"">>, <<"">>, _} -> <<"js">>;
|
|
|
|
{<<"">>, <<"">>, <<"">>, _, _} -> <<"text">>;
|
|
|
|
{<<"">>, <<"">>, _, _, _} -> <<"avatar">>;
|
|
|
|
{<<"">>, _, _, _, _} -> <<"xml">>;
|
|
|
|
{_, _, _, _, _} -> <<"image">>
|
2013-04-15 12:03:14 +02:00
|
|
|
end,
|
|
|
|
{USERID_jid, Example_jid} = case WP#webpresence.jidurl of
|
2014-04-08 00:10:05 +02:00
|
|
|
false -> {<<"">>, <<"">>};
|
|
|
|
true ->
|
|
|
|
JIDT = ?BC([<<"jid/">>, User, <<"/">>, Server]),
|
|
|
|
{?BC([<<" ">>, JIDT, <<"\n">>]),
|
|
|
|
?BC([<<" ">>, BaseURL, JIDT, <<"/">>, Allowed_type, <<"/\n">>])}
|
2013-04-15 12:03:14 +02:00
|
|
|
end,
|
|
|
|
{USERID_rid, Example_rid, Text_rid} = case WP#webpresence.ridurl of
|
2014-04-08 00:10:05 +02:00
|
|
|
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">>])
|
2013-04-15 12:03:14 +02:00
|
|
|
}
|
|
|
|
end,
|
2014-04-08 00:10:05 +02:00
|
|
|
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]),
|
2013-04-15 12:03:14 +02:00
|
|
|
send_headline(Host, To, Subject, Body).
|
|
|
|
|
|
|
|
send_message_unregistered(To, Host, Lang) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
Subject = ?BC([?T(<<"Web Presence">>), <<": ">>, ?T(<<"unregistered">>)]),
|
|
|
|
Body = ?BC([?T(<<"You have unregistered.">>), <<"\n\n">>]),
|
2013-04-15 12:03:14 +02:00
|
|
|
send_headline(Host, To, Subject, Body).
|
|
|
|
|
|
|
|
send_headline(Host, To, Subject, Body) ->
|
|
|
|
ejabberd_router:route(
|
2014-04-08 00:10:05 +02:00
|
|
|
jlib:make_jid(<<"">>, Host, <<"">>),
|
2013-04-15 12:03:14 +02:00
|
|
|
To,
|
2014-04-08 00:10:05 +02:00
|
|
|
#xmlel{
|
|
|
|
name = <<"message">>,
|
|
|
|
attrs = [{<<"type">>, <<"headline">>}],
|
|
|
|
children = [
|
|
|
|
#xmlel{
|
|
|
|
name = <<"subject">>,
|
|
|
|
attrs = [],
|
|
|
|
children = [{xmlcdata, Subject}]
|
|
|
|
},
|
|
|
|
#xmlel{
|
|
|
|
name = <<"body">>,
|
|
|
|
attrs = [],
|
|
|
|
children = [{xmlcdata, Body}]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}).
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
get_attr(Attr, XData, Default) ->
|
|
|
|
case lists:keysearch(Attr, 1, XData) of
|
|
|
|
{value, {_, [Value]}} -> Value;
|
|
|
|
false -> Default
|
|
|
|
end.
|
|
|
|
|
|
|
|
process_iq_register_set(From, SubEl, Host, BaseURL, Lang) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
#xmlel{name = _, attrs = _, children = Els} = SubEl,
|
|
|
|
case xml:get_subtag(SubEl, <<"remove">>) of
|
2013-04-15 12:03:14 +02:00
|
|
|
false -> case catch process_iq_register_set2(From, Els, Host, BaseURL, Lang) of
|
|
|
|
{'EXIT', _} -> {error, ?ERR_BAD_REQUEST};
|
|
|
|
R -> R
|
|
|
|
end;
|
|
|
|
_ -> unregister_webpresence(From, Host, Lang)
|
|
|
|
end.
|
|
|
|
|
|
|
|
process_iq_register_set2(From, Els, Host, BaseURL, Lang) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
[
|
|
|
|
#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">>} ->
|
2013-04-15 12:03:14 +02:00
|
|
|
{result, []};
|
2014-04-08 00:10:05 +02:00
|
|
|
{?NS_XDATA, <<"submit">>} ->
|
2013-04-15 12:03:14 +02:00
|
|
|
XData = jlib:parse_xdata_submit(XEl),
|
|
|
|
false = (invalid == XData),
|
2014-04-08 00:10:05 +02:00
|
|
|
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, <<"---">>),
|
2013-04-15 12:03:14 +02:00
|
|
|
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.
|
|
|
|
|
|
|
|
unregister_webpresence(From, Host, Lang) ->
|
|
|
|
{LUser, LServer, _} = jlib:jid_tolower(From),
|
|
|
|
remove_user(LUser, LServer),
|
|
|
|
send_message_unregistered(From, Host, Lang),
|
|
|
|
{result, []}.
|
|
|
|
|
|
|
|
remove_user(User, Server) ->
|
|
|
|
mnesia:dirty_delete(webpresence, {User, Server}).
|
|
|
|
|
|
|
|
iq_get_vcard() ->
|
2014-04-08 00:10:05 +02:00
|
|
|
[
|
|
|
|
#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 <antonio.murdaca@gmail.com>">>}]
|
|
|
|
}
|
|
|
|
].
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
get_wp(LUser, LServer) ->
|
|
|
|
LUS = {LUser, LServer},
|
|
|
|
case catch mnesia:dirty_read(webpresence, LUS) of
|
2014-04-08 00:10:05 +02:00
|
|
|
{'EXIT', _Reason} ->
|
2013-04-15 12:03:14 +02:00
|
|
|
try_auto_webpresence(LUser, LServer);
|
2014-04-08 00:10:05 +02:00
|
|
|
[] ->
|
2013-04-15 12:03:14 +02:00
|
|
|
try_auto_webpresence(LUser, LServer);
|
|
|
|
[WP] when is_record(WP, webpresence) ->
|
|
|
|
WP
|
|
|
|
end.
|
|
|
|
|
|
|
|
try_auto_webpresence(LUser, LServer) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
From = jlib:make_jid(LUser, LServer, <<"">>),
|
2013-04-15 12:03:14 +02:00
|
|
|
case acl:match_rule(LServer, ?AUTO_ACL, From) of
|
2014-04-08 00:10:05 +02:00
|
|
|
deny ->
|
2013-04-15 12:03:14 +02:00
|
|
|
#webpresence{};
|
2014-04-08 00:10:05 +02:00
|
|
|
allow ->
|
|
|
|
#webpresence{us = {LUser, LServer},
|
|
|
|
ridurl = false,
|
|
|
|
jidurl = true,
|
|
|
|
xml = true,
|
|
|
|
avatar = true,
|
|
|
|
js = true,
|
|
|
|
text = true,
|
|
|
|
icon = <<"jsf-jabber-text">>}
|
|
|
|
end.
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
get_status_weight(Show) ->
|
|
|
|
case Show of
|
2014-04-08 00:10:05 +02:00
|
|
|
<<"chat">> -> 0;
|
|
|
|
<<"available">> -> 1;
|
|
|
|
<<"away">> -> 2;
|
|
|
|
<<"xa">> -> 3;
|
|
|
|
<<"dnd">> -> 4;
|
|
|
|
_ -> 9
|
2013-04-15 12:03:14 +02:00
|
|
|
end.
|
|
|
|
|
|
|
|
session_to_presence(#session{sid = {_, Pid}, priority = Priority}) ->
|
|
|
|
{_User, Resource, Show, Status} = ejabberd_c2s:get_presence(Pid),
|
|
|
|
#presence{resource = Resource,
|
|
|
|
show = Show,
|
|
|
|
priority = Priority,
|
|
|
|
status = Status}.
|
|
|
|
|
|
|
|
get_presences({bare, LUser, LServer}) ->
|
|
|
|
[session_to_presence(Session) ||
|
|
|
|
Session <- mnesia:dirty_index_read(session, {LUser, LServer}, #session.us)];
|
2014-04-08 00:10:05 +02:00
|
|
|
|
2013-04-15 12:03:14 +02:00
|
|
|
get_presences({sorted, LUser, LServer}) ->
|
|
|
|
lists:sort(
|
|
|
|
fun(A, B) ->
|
|
|
|
if
|
|
|
|
A#presence.priority == B#presence.priority ->
|
|
|
|
WA = get_status_weight(A#presence.show),
|
|
|
|
WB = get_status_weight(B#presence.show),
|
|
|
|
WA < WB;
|
|
|
|
true ->
|
|
|
|
A#presence.priority > B#presence.priority
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
get_presences({bare, LUser, LServer}));
|
2014-04-08 00:10:05 +02:00
|
|
|
|
2013-04-15 12:03:14 +02:00
|
|
|
get_presences({xml, LUser, LServer, Show_us}) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
#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})
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
2013-04-15 12:03:14 +02:00
|
|
|
get_presences({status, LUser, LServer, LResource}) ->
|
|
|
|
case get_presences({sorted, LUser, LServer}) of
|
2014-04-08 00:10:05 +02:00
|
|
|
[] -> <<"unavailable">>;
|
|
|
|
Rs ->
|
2013-04-15 12:03:14 +02:00
|
|
|
{value, R} = lists:keysearch(LResource, 2, Rs),
|
2014-04-08 00:10:05 +02:00
|
|
|
R#presence.show %% TODO why was this "status"?!
|
2013-04-15 12:03:14 +02:00
|
|
|
end;
|
2014-04-08 00:10:05 +02:00
|
|
|
|
2013-04-15 12:03:14 +02:00
|
|
|
get_presences({status, LUser, LServer}) ->
|
|
|
|
case get_presences({sorted, LUser, LServer}) of
|
|
|
|
[Highest | _Rest] ->
|
2014-04-08 00:10:05 +02:00
|
|
|
Highest#presence.show; %% TODO why was this "status"?!
|
2013-04-15 12:03:14 +02:00
|
|
|
_ ->
|
2014-04-08 00:10:05 +02:00
|
|
|
<<"unavailable">>
|
2013-04-15 12:03:14 +02:00
|
|
|
end;
|
2014-04-08 00:10:05 +02:00
|
|
|
|
2013-04-15 12:03:14 +02:00
|
|
|
get_presences({show, LUser, LServer, LResource}) ->
|
|
|
|
case get_presences({sorted, LUser, LServer}) of
|
2014-04-08 00:10:05 +02:00
|
|
|
[] -> <<"unavailable">>;
|
|
|
|
Rs ->
|
2013-04-15 12:03:14 +02:00
|
|
|
{value, R} = lists:keysearch(LResource, 2, Rs),
|
|
|
|
R#presence.show
|
|
|
|
end;
|
2014-04-08 00:10:05 +02:00
|
|
|
|
2013-04-15 12:03:14 +02:00
|
|
|
get_presences({show, LUser, LServer}) ->
|
|
|
|
case get_presences({sorted, LUser, LServer}) of
|
|
|
|
[Highest | _Rest] ->
|
|
|
|
Highest#presence.show;
|
|
|
|
_ ->
|
2014-04-08 00:10:05 +02:00
|
|
|
<<"unavailable">>
|
2013-04-15 12:03:14 +02:00
|
|
|
end.
|
|
|
|
|
|
|
|
make_js(WP, Prs, Show_us, Lang, Q) ->
|
|
|
|
{User, Server} = WP#webpresence.us,
|
|
|
|
BaseURL = get_baseurl(Server),
|
|
|
|
US_string = case Show_us of
|
2014-04-08 00:10:05 +02:00
|
|
|
true ->
|
|
|
|
?BC([<<"var jabber_user='">>, User, <<"';\n">>, <<"var jabber_server='">>, Server, <<"';\n">>]); false -> <<"">>
|
2013-04-15 12:03:14 +02:00
|
|
|
end,
|
|
|
|
FunImage = fun(I, S) ->
|
|
|
|
case I of
|
2014-04-08 00:10:05 +02:00
|
|
|
<<"---">> -> <<"">>;
|
|
|
|
Icon -> ?BC([<<" image:'">>, BaseURL, <<"image/">>, Icon, <<"/">>, S, <<"'\n">>])
|
2013-04-15 12:03:14 +02:00
|
|
|
end
|
|
|
|
end,
|
|
|
|
R_string_list = case Prs of
|
2014-04-08 00:10:05 +02:00
|
|
|
[] ->
|
|
|
|
Show = <<"unavailable">>,
|
|
|
|
[?BC([<<"{show:'">>, Show, <<"',\n">>,
|
|
|
|
<<" long_show:'">>, long_show(Show, Lang), <<"',\n">>,
|
|
|
|
<<" status:'',\n">>, % TODO
|
|
|
|
FunImage(WP#webpresence.icon, Show),
|
|
|
|
<<"}">>])];
|
2013-04-15 12:03:14 +02:00
|
|
|
_ -> lists:map(
|
|
|
|
fun(Pr) ->
|
|
|
|
Show = Pr#presence.show,
|
2014-04-08 00:10:05 +02:00
|
|
|
?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),
|
|
|
|
<<"}">>])
|
2013-04-15 12:03:14 +02:00
|
|
|
end,
|
|
|
|
Prs)
|
|
|
|
end,
|
|
|
|
R_string = lists:foldl(
|
|
|
|
fun(RS, Res) ->
|
|
|
|
case Res of
|
2014-04-08 00:10:05 +02:00
|
|
|
<<"">> -> RS;
|
|
|
|
_ -> ?BC([Res, <<",\n">>, RS])
|
2013-04-15 12:03:14 +02:00
|
|
|
end
|
|
|
|
end,
|
2014-04-08 00:10:05 +02:00
|
|
|
<<"">>,
|
2013-04-15 12:03:14 +02:00
|
|
|
R_string_list),
|
2014-04-08 00:10:05 +02:00
|
|
|
CB_string = case lists:keysearch(<<"cb">>, 1, Q) of
|
|
|
|
{value, {_, CB}} -> ?BC([<<" ">>, CB, <<"();">>]);
|
|
|
|
_ -> <<"">>
|
2013-04-15 12:03:14 +02:00
|
|
|
end,
|
2014-04-08 00:10:05 +02:00
|
|
|
?BC([US_string, <<"var jabber_resources=[\n">>, R_string, <<"];">>, CB_string]).
|
2013-04-15 12:03:14 +02:00
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
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">>).
|
2013-04-15 12:03:14 +02:00
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
intund2string(undefined) -> <<"undefined">>;
|
|
|
|
intund2string(Int) when is_integer(Int) -> list_to_binary(integer_to_list(Int)).
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
escape(S1) ->
|
2013-09-10 18:34:38 +02:00
|
|
|
S2 = re:replace(S1, "\'", "\\'", [global, {return, list}]),
|
|
|
|
re:replace(S2, "\n", "\\n", [global, {return, list}]).
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
get_baseurl(Host) ->
|
|
|
|
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
|
|
|
|
Proc ! {tell_baseurl, self()},
|
2014-04-08 00:10:05 +02:00
|
|
|
receive
|
2013-04-15 12:03:14 +02:00
|
|
|
{baseurl_is, BaseURL} -> BaseURL
|
|
|
|
end.
|
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
-define(XML_HEADER, <<"<?xml version='1.0' encoding='utf-8'?>">>).
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
get_pixmaps_directory() ->
|
|
|
|
[{directory, Path} | _] = ets:lookup(pixmaps_dirs, directory),
|
|
|
|
Path.
|
|
|
|
|
|
|
|
available_themes(list) ->
|
|
|
|
case file:list_dir(get_pixmaps_directory()) of
|
|
|
|
{ok, List} ->
|
|
|
|
L2 = lists:sort(List),
|
|
|
|
%% Remove from the list of themes the directories that start with a dot
|
|
|
|
[T || T <- L2, hd(T) =/= 46];
|
|
|
|
{error, _} ->
|
|
|
|
[]
|
|
|
|
end;
|
2014-04-08 00:10:05 +02:00
|
|
|
|
2013-04-15 12:03:14 +02:00
|
|
|
available_themes(xdata) ->
|
|
|
|
lists:map(
|
|
|
|
fun(Theme) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
#xmlel{
|
|
|
|
name = <<"option">>,
|
|
|
|
attrs = [{<<"label">>, iolist_to_binary(Theme)}],
|
|
|
|
children = [
|
|
|
|
#xmlel{
|
|
|
|
name = <<"value">>,
|
|
|
|
attrs = [],
|
|
|
|
children = [{xmlcdata, iolist_to_binary(Theme)}]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
2013-04-15 12:03:14 +02:00
|
|
|
end, available_themes(list)).
|
|
|
|
|
|
|
|
show_presence({image_no_check, Theme, Pr}) ->
|
|
|
|
Dir = get_pixmaps_directory(),
|
2014-04-08 00:10:05 +02:00
|
|
|
Image = ?BC([Pr, <<".{gif,png,jpg}">>]),
|
|
|
|
[First | _Rest] = filelib:wildcard(binary_to_list(filename:join([Dir, Theme, Image]))),
|
2013-04-15 12:03:14 +02:00
|
|
|
Mime = string:substr(First, string:len(First) - 2, 3),
|
|
|
|
{ok, Content} = file:read_file(First),
|
2014-04-08 00:10:05 +02:00
|
|
|
{200, [{<<"Content-Type">>, ?BC([<<"image/">>, ?BC(Mime)])}], binary_to_list(Content)};
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
show_presence({image, WP, LUser, LServer}) ->
|
|
|
|
Icon = WP#webpresence.icon,
|
2014-04-08 00:10:05 +02:00
|
|
|
false = (<<"---">> == Icon),
|
2013-04-15 12:03:14 +02:00
|
|
|
Pr = get_presences({show, LUser, LServer}),
|
|
|
|
show_presence({image_no_check, Icon, Pr});
|
|
|
|
|
|
|
|
show_presence({image, WP, LUser, LServer, Theme}) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
false = (<<"---">> == WP#webpresence.icon),
|
2013-04-15 12:03:14 +02:00
|
|
|
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,
|
2014-04-08 00:10:05 +02:00
|
|
|
false = (<<"---">> == Icon),
|
2013-04-15 12:03:14 +02:00
|
|
|
Pr = get_presences({show, LUser, LServer, LResource}),
|
|
|
|
show_presence({image_no_check, Icon, Pr});
|
|
|
|
|
|
|
|
show_presence({image_res, WP, LUser, LServer, Theme, LResource}) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
false = (<<"---">> == WP#webpresence.icon),
|
2013-04-15 12:03:14 +02:00
|
|
|
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,
|
2014-04-08 00:10:05 +02:00
|
|
|
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])};
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
show_presence({js, WP, LUser, LServer, Show_us, Lang, Q}) ->
|
|
|
|
true = WP#webpresence.js,
|
|
|
|
Prs = get_presences({sorted, LUser, LServer}),
|
|
|
|
Js = make_js(WP, Prs, Show_us, Lang, Q),
|
|
|
|
{200, [{"Content-Type", "text/html; charset=utf-8"}], Js};
|
|
|
|
|
|
|
|
show_presence({text, WP, LUser, LServer}) ->
|
|
|
|
true = WP#webpresence.text,
|
|
|
|
Presence_text = get_presences({status, LUser, LServer}),
|
|
|
|
{200, [{"Content-Type", "text/html; charset=utf-8"}], Presence_text};
|
|
|
|
|
|
|
|
show_presence({text, WP, LUser, LServer, LResource}) ->
|
|
|
|
true = WP#webpresence.text,
|
|
|
|
Presence_text = get_presences({status, LUser, LServer, LResource}),
|
|
|
|
{200, [{"Content-Type", "text/html; charset=utf-8"}], Presence_text};
|
|
|
|
|
|
|
|
show_presence({avatar, WP, LUser, LServer}) ->
|
|
|
|
true = WP#webpresence.avatar,
|
|
|
|
[{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, LServer}),
|
2014-04-08 00:10:05 +02:00
|
|
|
JID = jlib:make_jid(LUser, LServer, <<"">>),
|
2013-04-15 12:03:14 +02:00
|
|
|
IQ = #iq{type = get, xmlns = ?NS_VCARD},
|
|
|
|
IQr = Module:Function(JID, JID, IQ),
|
|
|
|
[VCard] = IQr#iq.sub_el,
|
2014-04-08 00:10:05 +02:00
|
|
|
Mime = xml:get_path_s(VCard, [{elem, <<"PHOTO">>}, {elem, <<"TYPE">>}, cdata]),
|
|
|
|
BinVal = xml:get_path_s(VCard, [{elem, <<"PHOTO">>}, {elem, <<"BINVAL">>}, cdata]),
|
2013-04-15 12:03:14 +02:00
|
|
|
Photo = jlib:decode_base64(BinVal),
|
|
|
|
{200, [{"Content-Type", Mime}], Photo};
|
|
|
|
|
|
|
|
show_presence({image_example, Theme, Show}) ->
|
|
|
|
Dir = get_pixmaps_directory(),
|
2014-04-08 00:10:05 +02:00
|
|
|
Image = ?BC([Show, <<".{gif,png,jpg}">>]),
|
|
|
|
[First | _Rest] = filelib:wildcard(binary_to_list(filename:join([Dir, Theme, Image]))),
|
2013-04-15 12:03:14 +02:00
|
|
|
Mime = string:substr(First, string:len(First) - 2, 3),
|
|
|
|
{ok, Content} = file:read_file(First),
|
2014-04-08 00:10:05 +02:00
|
|
|
{200, [{<<"Content-Type">>, ?BC([<<"image/">>, ?BC(Mime)])}], binary_to_list(Content)}.
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
%% ---------------------
|
|
|
|
%% Web Publish
|
|
|
|
%% ---------------------
|
|
|
|
|
|
|
|
make_xhtml(Els) -> make_xhtml([], Els).
|
|
|
|
make_xhtml(Title, Els) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
#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
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}.
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
themes_to_xhtml(Themes) ->
|
|
|
|
ShowL = ["available", "chat", "dnd", "away", "xa", "unavailable"],
|
|
|
|
THeadL = [""] ++ ShowL,
|
2014-04-08 00:10:05 +02:00
|
|
|
[?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]
|
2013-04-15 12:03:14 +02:00
|
|
|
]
|
|
|
|
) || Theme <- Themes]
|
|
|
|
)
|
|
|
|
].
|
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
parse_lang(Lang) -> iolist_to_binary(hd(string:tokens(binary_to_list(Lang),"-"))).
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
process(LocalPath, Request) ->
|
|
|
|
case catch process2(LocalPath, Request) of
|
|
|
|
{'EXIT', Reason} ->
|
2014-04-08 00:10:05 +02:00
|
|
|
?DEBUG("~p", [Request]),
|
2013-04-15 12:03:14 +02:00
|
|
|
?DEBUG("The call to path ~p in the~nrequest: ~p~ncrashed with error: ~p", [LocalPath, Request, Reason]),
|
2014-04-08 00:10:05 +02:00
|
|
|
{404, [], make_xhtml([?XC(<<"h1">>, <<"Not found">>)])};
|
2013-04-15 12:03:14 +02:00
|
|
|
Res ->
|
|
|
|
Res
|
|
|
|
end.
|
|
|
|
|
|
|
|
process2([], #request{lang = Lang1}) ->
|
|
|
|
Lang = parse_lang(Lang1),
|
2014-04-08 00:10:05 +02:00
|
|
|
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,
|
2013-04-15 12:03:14 +02:00
|
|
|
make_xhtml(Title, Body);
|
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
process2([<<"themes">>], #request{lang = Lang1}) ->
|
2013-04-15 12:03:14 +02:00
|
|
|
Lang = parse_lang(Lang1),
|
2014-04-08 00:10:05 +02:00
|
|
|
Title = [?XC(<<"title">>, ?BC([?T(<<"Web Presence">>), <<" - ">>, ?T("Icon Theme")]))],
|
2013-04-15 12:03:14 +02:00
|
|
|
Themes = available_themes(list),
|
|
|
|
Icon_themes = themes_to_xhtml(Themes),
|
2014-04-08 00:10:05 +02:00
|
|
|
Body = [?XC(<<"h1">>, ?T(<<"Icon Theme">>))] ++ Icon_themes,
|
2013-04-15 12:03:14 +02:00
|
|
|
make_xhtml(Title, Body);
|
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
process2([<<"image">>, Theme, Show], #request{} = _Request) ->
|
2013-04-15 12:03:14 +02:00
|
|
|
Args = {image_example, Theme, Show},
|
|
|
|
show_presence(Args);
|
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
process2([<<"jid">>, User, Server | Tail], Request) ->
|
2013-04-15 12:03:14 +02:00
|
|
|
serve_web_presence(jid, User, Server, Tail, Request);
|
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
process2([<<"rid">>, Rid | Tail], Request) ->
|
2013-04-15 12:03:14 +02:00
|
|
|
[Pr] = mnesia:dirty_index_read(webpresence, Rid, #webpresence.ridurl),
|
|
|
|
{User, Server} = Pr#webpresence.us,
|
|
|
|
serve_web_presence(rid, User, Server, Tail, Request);
|
|
|
|
|
|
|
|
%% Compatibility with old mod_presence
|
|
|
|
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),
|
2014-04-08 00:10:05 +02:00
|
|
|
true = lists:member(Server, ?MYHOSTS),
|
2013-04-15 12:03:14 +02:00
|
|
|
LUser = jlib:nodeprep(User),
|
|
|
|
WP = get_wp(LUser, LServer),
|
|
|
|
case TypeURL of
|
|
|
|
jid -> true = WP#webpresence.jidurl;
|
2014-04-08 00:10:05 +02:00
|
|
|
rid -> true = is_binary(WP#webpresence.ridurl)
|
2013-04-15 12:03:14 +02:00
|
|
|
end,
|
|
|
|
Show_us = (TypeURL == jid),
|
|
|
|
Lang = parse_lang(Lang1),
|
|
|
|
Args = case Tail of
|
2014-04-08 00:10:05 +02:00
|
|
|
[<<"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}
|
2013-04-15 12:03:14 +02:00
|
|
|
end,
|
|
|
|
show_presence(Args).
|
|
|
|
|
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
%%%% ---------------------
|
|
|
|
%%%% Web Admin
|
|
|
|
%%%% ---------------------
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
web_menu_host(Acc, _Host, Lang) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
[{<<"webpresence">>, ?T(<<"Web Presence">>)} | Acc].
|
2013-04-15 12:03:14 +02:00
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
web_page_host(_, _Host,
|
|
|
|
#request{path = [<<"webpresence">>],
|
2013-04-15 12:03:14 +02:00
|
|
|
lang = Lang} = _Request) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
Res = [?XCT(<<"h1">>, <<"Web Presence">>),
|
|
|
|
?XE(<<"ul">>, [
|
|
|
|
?LI([?ACT(<<"stats">>, <<"Statistics">>)]),
|
|
|
|
?LI([?ACT(<<"users">>, <<"Registered Users">>)])])],
|
2013-04-15 12:03:14 +02:00
|
|
|
{stop, Res};
|
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
web_page_host(_, Host,
|
|
|
|
#request{path = [<<"webpresence">>, <<"users">>],
|
2013-04-15 12:03:14 +02:00
|
|
|
lang = Lang} = _Request) ->
|
|
|
|
Users = get_users(Host),
|
|
|
|
Table = make_users_table(Users, Lang),
|
2014-04-08 00:10:05 +02:00
|
|
|
Res = [?XCT(<<"h1">>, <<"Web Presence">>),
|
|
|
|
?XCT(<<"h2">>, <<"Registered Users">>)] ++ Table,
|
2013-04-15 12:03:14 +02:00
|
|
|
{stop, Res};
|
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
web_page_host(_, Host,
|
|
|
|
#request{path = [<<"webpresence">>, <<"stats">>],
|
2013-04-15 12:03:14 +02:00
|
|
|
lang = Lang} = _Request) ->
|
|
|
|
Users = get_users(Host),
|
2014-04-08 00:10:05 +02:00
|
|
|
Res = [?XCT(<<"h1">>, <<"Web Presence">>),
|
2013-04-15 12:03:14 +02:00
|
|
|
css_table(),
|
2014-04-08 00:10:05 +02:00
|
|
|
?XCT(<<"h2">>, <<"Statistics">>)]
|
2013-04-15 12:03:14 +02:00
|
|
|
++ make_stats_options(Users, Lang)
|
|
|
|
++ make_stats_iconthemes(Users, Lang),
|
|
|
|
{stop, Res};
|
|
|
|
|
2014-04-08 00:10:05 +02:00
|
|
|
web_page_host(Acc, _, _) -> Acc.
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
get_users(Host) ->
|
|
|
|
Select = [{{webpresence, {'$1', Host}, '$2', '$3', '$4', '$5', '$6', '$7', '$8'}, [], ['$$']}],
|
|
|
|
mnesia:dirty_select(webpresence, Select).
|
|
|
|
|
|
|
|
make_users_table(Records, Lang) ->
|
|
|
|
TList = lists:map(
|
|
|
|
fun([User, RidUrl, JIDUrl, XML, Avatar, JS, Text, Icon]) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
?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)))])
|
2013-04-15 12:03:14 +02:00
|
|
|
end, Records),
|
2014-04-08 00:10:05 +02:00
|
|
|
[?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">>)
|
2013-04-15 12:03:14 +02:00
|
|
|
])]),
|
2014-04-08 00:10:05 +02:00
|
|
|
?XE(<<"tbody">>, TList)])].
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
make_stats_options(Records, Lang) ->
|
|
|
|
[RegUsers, JJ, RR, XX, AA, SS, TT, II] = lists:foldl(
|
|
|
|
fun([_User, RidUrl, JidUrl, XML, Avatar, JS, Text, Icon], [N, J, R, X, A, S, T, I]) ->
|
|
|
|
J2 = J + case JidUrl of false -> 0; true -> 1 end,
|
|
|
|
R2 = R + case RidUrl of false -> 0; _ -> 1 end,
|
|
|
|
X2 = X + case XML of false -> 0; true -> 1 end,
|
|
|
|
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,
|
2014-04-08 00:10:05 +02:00
|
|
|
I2 = I + case Icon of <<"---">> -> 0; _ -> 1 end,
|
2013-04-15 12:03:14 +02:00
|
|
|
[N+1, J2, R2, X2, A2, S2, T2, I2]
|
2014-04-08 00:10:05 +02:00
|
|
|
end,
|
2013-04-15 12:03:14 +02:00
|
|
|
[0, 0, 0, 0, 0, 0, 0, 0],
|
|
|
|
Records),
|
2014-04-08 00:10:05 +02:00
|
|
|
URLTList = [{<<"Jabber ID">>, JJ}, {<<"Random ID">>, RR}],
|
|
|
|
OutputTList = [{<<"Icon Theme">>, II}, {<<"XML">>, XX}, {<<"JavaScript">>, SS}, {<<"Text">>, TT}, {<<"Avatar">>, AA}],
|
2013-04-15 12:03:14 +02:00
|
|
|
[
|
2014-04-08 00:10:05 +02:00
|
|
|
?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))]
|
2013-04-15 12:03:14 +02:00
|
|
|
),
|
2014-04-08 00:10:05 +02:00
|
|
|
?XCT(<<"h3">>, <<"Output Type">>),
|
|
|
|
?XAE(<<"table">>, [{<<"class">>, <<"stats">>}],
|
|
|
|
[?XE(<<"tbody">>, do_stat_table_with(OutputTList, RegUsers))]
|
2013-04-15 12:03:14 +02:00
|
|
|
)].
|
|
|
|
|
|
|
|
make_stats_iconthemes(Records, Lang) ->
|
|
|
|
Themes1 = [{T, 0} || T <- available_themes(list)],
|
|
|
|
Dict = lists:foldl(
|
|
|
|
fun([_, _, _, _, _, _, _, Icon], D) ->
|
|
|
|
dict:update_counter(Icon, 1, D)
|
2014-04-08 00:10:05 +02:00
|
|
|
end,
|
2013-04-15 12:03:14 +02:00
|
|
|
dict:from_list(Themes1),
|
|
|
|
Records),
|
|
|
|
Themes = lists:keysort(1, dict:to_list(Dict)),
|
2014-04-08 00:10:05 +02:00
|
|
|
[?XCT(<<"h3">>, <<"Icon Theme">>),
|
|
|
|
?XAE(<<"table">>, [{<<"class">>, <<"stats">>}],
|
|
|
|
[?XE(<<"tbody">>, do_stat_table_with(Themes))]
|
2013-04-15 12:03:14 +02:00
|
|
|
)].
|
|
|
|
|
|
|
|
%% Do table with bars
|
|
|
|
do_stat_table_with(Values) ->
|
|
|
|
Ns = [Ni || {_, Ni} <- Values],
|
|
|
|
Total = lists:sum(Ns),
|
|
|
|
do_stat_table_with(Values, Total).
|
|
|
|
|
|
|
|
do_stat_table_with(Values, Total) ->
|
|
|
|
lists:map(
|
2014-04-08 00:10:05 +02:00
|
|
|
fun({L, N}) ->
|
2013-04-15 12:03:14 +02:00
|
|
|
Perc = case Total of
|
2014-04-08 00:10:05 +02:00
|
|
|
0 -> <<"0">>;
|
|
|
|
_ -> iolist_to_binary(integer_to_list(trunc(100 * N / Total)))
|
2013-04-15 12:03:14 +02:00
|
|
|
end,
|
|
|
|
do_table_element(?C(L), io_lib:format("~p", [N]), Perc)
|
|
|
|
end,
|
|
|
|
Values).
|
|
|
|
do_table_element(L, [N], Perc) ->
|
2014-04-08 00:10:05 +02:00
|
|
|
?XE(<<"tr">>,
|
|
|
|
[?XE(<<"td">>, [L]),
|
|
|
|
?XAC(<<"td">>, [{<<"class">>, <<"alignright">>}], [N]),
|
|
|
|
?XE(<<"td">>,
|
|
|
|
[?XAE(<<"div">>,
|
|
|
|
[{<<"class">>, <<"graph">>}],
|
|
|
|
[?XAC(<<"div">>,
|
|
|
|
[{<<"class">>, <<"bar">>}, {<<"style">>, ?BC([<<"width: ">>, Perc, <<"%;">>])}],
|
2013-04-15 12:03:14 +02:00
|
|
|
[]
|
|
|
|
)]
|
|
|
|
)]
|
|
|
|
),
|
2014-04-08 00:10:05 +02:00
|
|
|
?XAC(<<"td">>, [{<<"class">>, <<"alignright">>}], [?BC([Perc, <<"%">>])])
|
2013-04-15 12:03:14 +02:00
|
|
|
]).
|
2014-04-08 00:10:05 +02:00
|
|
|
|
2013-04-15 12:03:14 +02:00
|
|
|
css_table()->
|
2014-04-08 00:10:05 +02:00
|
|
|
?XAE(<<"style">>, [{<<"type">>, <<"text/css">>}],
|
|
|
|
[?C(<<".stats {
|
2013-04-15 12:03:14 +02:00
|
|
|
padding-left: 20px;
|
|
|
|
padding-top: 10px;
|
|
|
|
}
|
|
|
|
.graph {
|
|
|
|
position: relative;
|
|
|
|
width: 200px;
|
|
|
|
border: 1px solid #D47911;
|
|
|
|
padding: 1px;
|
|
|
|
}
|
|
|
|
.graph .bar {
|
|
|
|
display: block;
|
|
|
|
position: relative;
|
|
|
|
background: #FFE3C9;
|
|
|
|
text-align: center;
|
|
|
|
color: #333;
|
|
|
|
height: 1.5em;
|
|
|
|
line-height: 1.5em;
|
|
|
|
}
|
2014-04-08 00:10:05 +02:00
|
|
|
.graph .bar span { position: absolute; left: 1em; }">>)]).
|
2013-04-15 12:03:14 +02:00
|
|
|
|
|
|
|
|
|
|
|
%%%--------------------------------
|
|
|
|
%%% Update table schema and content from older versions
|
|
|
|
%%%--------------------------------
|
|
|
|
|
|
|
|
update_table() ->
|
|
|
|
case catch mnesia:table_info(presence_registered, size) of
|
|
|
|
Size when is_integer(Size) -> catch migrate_data_mod_presence(Size);
|
|
|
|
_ -> ok
|
|
|
|
end.
|
|
|
|
|
|
|
|
migrate_data_mod_presence(Size) ->
|
|
|
|
Migrate = fun(Old, S) ->
|
|
|
|
{presence_registered, {US, _Host}, XML, Icon} = Old,
|
|
|
|
New = #webpresence{us = US,
|
|
|
|
ridurl = false,
|
|
|
|
jidurl = true,
|
|
|
|
xml = list_to_atom(XML),
|
|
|
|
avatar = false,
|
|
|
|
js = false,
|
|
|
|
text = false,
|
|
|
|
icon = Icon},
|
|
|
|
mnesia:write(New),
|
|
|
|
mnesia:delete_object(Old),
|
|
|
|
S-1
|
|
|
|
end,
|
|
|
|
F = fun() -> mnesia:foldl(Migrate, Size, presence_registered) end,
|
|
|
|
{atomic, 0} = mnesia:transaction(F),
|
|
|
|
{atomic, ok} = mnesia:delete_table(presence_registered).
|