From 721ca125ea0b8f5d16c2855b114eb6715cfad9d4 Mon Sep 17 00:00:00 2001 From: Badlop Date: Sat, 28 Apr 2018 11:27:31 +0200 Subject: [PATCH] Update to work with recent ejabberd TODO: - Registration does not support enabling/disabling different features - Avatar does not work at all - Check all he configurable options are really used --- mod_webpresence/src/mod_webpresence.erl | 560 +++++++++++------------- 1 file changed, 245 insertions(+), 315 deletions(-) diff --git a/mod_webpresence/src/mod_webpresence.erl b/mod_webpresence/src/mod_webpresence.erl index d4dce26..af8d4fe 100644 --- a/mod_webpresence/src/mod_webpresence.erl +++ b/mod_webpresence/src/mod_webpresence.erl @@ -12,51 +12,48 @@ -behaviour(gen_mod). %% API --export([start_link/2, - start/2, +-export([start/2, stop/1, remove_user/2, web_menu_host/3, web_page_host/3, + process_disco_info/1, + process_disco_items/1, + process_vcard/1, + process_register/1, process/2 ]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). + terminate/2, code_change/3, + mod_opt_type/1, mod_options/1, depends/2]). + +%% API +-export([start_link/0]). -include("ejabberd.hrl"). --include("jlib.hrl"). +-include("xmpp.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(webpresence, {us, ridurl = false, jidurl = false, xml = false, avatar = false, js = false, text = false, icon = "jsf-text"}). -record(state, {host, server_host, base_url, access}). --record(presence, {resource, show, priority, status}). +-record(presence2, {resource, show, priority, status}). %% Copied from ejabberd_sm.erl -record(session, {sid, usr, us, priority, info}). --define(PROCNAME, ejabberd_mod_webpresence). -define(PIXMAPS_DIR, <<"pixmaps">>). -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_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). start(Host, Opts) -> - Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - 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]) @@ -64,13 +61,42 @@ start(Host, Opts) -> 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). + case gen_mod:start_child(?MODULE, Host, Opts) of + {ok, Ref} -> + {ok, Ref}; + {error, {already_started, Ref}} -> + {ok, Ref}; + {error, Reason} -> + {error, Reason} + end. stop(Host) -> - Proc = gen_mod:get_module_proc(Host, ?PROCNAME), + Proc = gen_mod:get_module_proc(Host, ?MODULE), gen_server:call(Proc, stop), - supervisor:terminate_child(ejabberd_sup, Proc), - supervisor:delete_child(ejabberd_sup, Proc). + gen_mod:stop_child(?MODULE, Host), + ok. + +-spec mod_opt_type(atom()) -> fun((term()) -> term()). +mod_opt_type(host) -> fun iolist_to_binary/1; +mod_opt_type(access) -> fun acl:access_rules_validator/1; +mod_opt_type(pixmaps_path) -> fun iolist_to_binary/1; +mod_opt_type(port) -> + fun(I) when is_integer(I), I>0, I<65536 -> I end; +mod_opt_type(path) -> fun iolist_to_binary/1; +mod_opt_type(baseurl) -> fun iolist_to_binary/1. + +-spec mod_options(binary()) -> [{atom(), any()}]. +mod_options(Host) -> + [{host, <<"webpresence.@HOST@">>}, + {access, none}, + {pixmaps_path, ?PIXMAPS_DIR}, + {port, 5280}, + {path, <<"presence">>}, + {baseurl, iolist_to_binary(io_lib:format(<<"http://~s:5280/presence/">>, [Host]))}]. + +-spec depends(binary(), gen_mod:opts()) -> [{module(), hard | soft}]. +depends(_Host, _Opts) -> + []. %%==================================================================== %% gen_server callbacks @@ -96,7 +122,8 @@ init([Host, Opts]) -> 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), - ejabberd_router:register_route(MyHost), + register_iq_handlers(MyHost), + ejabberd_router:register_route(MyHost, Host), 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), @@ -105,6 +132,22 @@ init([Host, Opts]) -> base_url = BaseURL2, access = Access}}. +register_iq_handlers(Host) -> + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_REGISTER, + ?MODULE, process_register), + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD, + ?MODULE, process_vcard), + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO, + ?MODULE, process_disco_info), + gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS, + ?MODULE, process_disco_items). + +unregister_iq_handlers(Host) -> + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_REGISTER), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_INFO), + gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_DISCO_ITEMS). + %%-------------------------------------------------------------------- %% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} | %% {reply, Reply, State, Timeout} | @@ -132,26 +175,19 @@ handle_cast(_Msg, State) -> %% {stop, Reason, State} %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- -handle_info({route, From, To, Packet}, +handle_info({route, Packet}, #state{host = Host, server_host = ServerHost, base_url = BaseURL, access = Access} = State) -> + From = xmpp:get_from(Packet), + To = xmpp:get_to(Packet), 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}. %%-------------------------------------------------------------------- @@ -163,6 +199,7 @@ handle_info(_Info, State) -> %%-------------------------------------------------------------------- terminate(_Reason, #state{host = Host}) -> ejabberd_router:unregister_route(Host), + unregister_iq_handlers(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), @@ -183,100 +220,86 @@ do_route(Host, ServerHost, Access, From, To, Packet, BaseURL) -> allow -> do_route1(Host, From, To, Packet, BaseURL); _ -> - #xmlel{attrs = Attrs} = Packet, - Lang = fxml:get_attr_s(<<"xml:lang">>, Attrs), + Lang = xmpp:get_lang(Packet), ErrText = <<"Access denied by service policy">>, - Err = jlib:make_error_reply(Packet, ?ERRT_FORBIDDEN(Lang, ErrText)), - ejabberd_router:route(To, From, Err) + Err = xmpp:err_forbidden(ErrText, Lang), + ejabberd_router:route_error(Packet, Err) end. -do_route1(Host, From, To, Packet, BaseURL) -> - #xmlel{name = Name, attrs = Attrs} = Packet, - case Name of - <<"iq">> -> do_route1_iq(Host, From, To, Packet, BaseURL, jlib:iq_query_info(Packet)); - _ -> case fxml: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 +-spec process_vcard(iq()) -> iq(). +process_vcard(#iq{type = get, lang = Lang, sub_els = [#vcard_temp{}]} = IQ) -> + Desc = translate:translate(Lang, <<"ejabberd Web Presence module">>), + xmpp:make_iq_result( + IQ, #vcard_temp{fn = <<"ejabberd/mod_webpresence">>, + url = ?EJABBERD_URI, + desc = <>}); +process_vcard(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_vcard(#iq{lang = Lang} = IQ) -> + Txt = <<"No module is handling this query">>, + xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)). + +do_route1(_Host, _From, _To, #iq{} = IQ, _BaseURL) -> + ejabberd_local:process_iq(IQ); +do_route1(_Host, _From, _To, Packet, _BaseURL) -> + case xmpp:get_type(Packet) of + error -> ok; + result -> ok; + _ -> + Err = xmpp:err_item_not_found(), + ejabberd_router:route_error(Packet, Err) end. -do_route1_iq(_, From, To, _, _, - #iq{type = get, xmlns = ?NS_DISCO_INFO, lang = Lang} = IQ) -> - 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)); +-spec process_register(iq()) -> iq(). +process_register(#iq{type = get, from = From, to = To, lang = Lang, + sub_els = [#register{}]} = IQ) -> + Host = To#jid.lserver, + ServerHost = ejabberd_router:host_of_route(Host), + xmpp:make_iq_result(IQ, iq_get_register_info(Host, From, Lang)); +process_register(#iq{type = set, from = From, to = To, + lang = Lang, sub_els = [El = #register{}]} = IQ) -> + Host = To#jid.lserver, + ServerHost = ejabberd_router:host_of_route(Host), + case process_iq_register_set(ServerHost, Host, From, El, Lang) of + {result, Result} -> + xmpp:make_iq_result(IQ, Result); + {error, Err} -> + xmpp:make_error(IQ, Err) + end. -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) -> - 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)); +-spec process_disco_info(iq()) -> iq(). +process_disco_info(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_disco_info(#iq{type = get, lang = Lang, + sub_els = [#disco_info{node = <<"">>}]} = IQ) -> + Features = [?NS_DISCO_INFO, ?NS_DISCO_ITEMS, + ?NS_REGISTER, ?NS_VCARD], + Identity = #identity{category = <<"component">>, + type = <<"presence">>, + name = translate:translate(Lang, <<"Web Presence">>)}, + xmpp:make_iq_result( + IQ, #disco_info{features = Features, + identities = [Identity]}); +process_disco_info(#iq{type = get, lang = Lang, + sub_els = [#disco_info{}]} = IQ) -> + xmpp:make_error(IQ, xmpp:err_item_not_found(<<"Node not found">>, Lang)); +process_disco_info(#iq{lang = Lang} = IQ) -> + Txt = <<"No module is handling this query">>, + xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)). -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 = #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} -> - 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) -> - 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), - ejabberd_router:route(To, From, Err); - -do_route1_iq(_, _, _, _, _, _) -> - ok. - -iq_disco_info(Lang) -> - [#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 = [] - }]. +-spec process_disco_items(iq()) -> iq(). +process_disco_items(#iq{type = set, lang = Lang} = IQ) -> + Txt = <<"Value 'set' of 'type' attribute is not allowed">>, + xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang)); +process_disco_items(#iq{type = get, + sub_els = [#disco_items{}]} = IQ) -> + xmpp:make_iq_result(IQ, #disco_items{}); +process_disco_items(#iq{lang = Lang} = IQ) -> + Txt = <<"No module is handling this query">>, + xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)). -define(XFIELDS(Type, Label, Var, Vals), #xmlel{ @@ -319,124 +342,94 @@ iq_disco_info(Lang) -> 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} + [#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} 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), - RegisteredXML = case Registered of - true -> [#xmlel{name = <<"registered">>, attrs = [], children = []}]; - false -> [] - end, - RegisteredXML ++ - [ - #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)) - ] - } - ]. +iq_get_register_info(Host, From, Lang) -> + LUS = {From#jid.luser, From#jid.lserver}, + {_JidUrl, _RidUrl, _XML, _Avatar, _JS, _Text, Icon, Registered} = get_pr(LUS), + Nick = Icon, + Title = <<(translate:translate( + Lang, <<"Web Presence Registration at ">>))/binary, Host/binary>>, + Inst = translate:translate(Lang, <<"Enter iconset you want to use by default">>), + Fields = muc_register:encode([{roomnick, Nick}], Lang), + X = #xdata{type = form, title = Title, + instructions = [Inst], fields = Fields}, + #register{nick = Nick, + registered = Registered, + instructions = + translate:translate( + Lang, <<"You need a client that supports x:data " + "to register to Web Presence">>), + xdata = X}. -%%%% 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 =/= <<"---">>), - case Check_URLTypes and Check_OutputTypes of - true -> iq_set_register_info2(From, LUS, Opts); - false -> unregister_webpresence(From, Host, Lang) +process_iq_register_set(ServerHost, Host, From, + #register{remove = true}, Lang) -> + unregister_webpresence(From, Host, Lang); +process_iq_register_set(_ServerHost, _Host, _From, + #register{xdata = #xdata{type = cancel}}, _Lang) -> + {result, undefined}; +process_iq_register_set(ServerHost, Host, From, + #register{nick = Nick, xdata = XData}, Lang) -> + case XData of + #xdata{type = submit, fields = Fs} -> + try + Options = muc_register:decode(Fs), + N = proplists:get_value(roomnick, Options), + iq_set_register_info(ServerHost, Host, From, N, Lang) + catch _:{muc_register, Why} -> + ErrText = muc_register:format_error(Why), + {error, xmpp:err_bad_request(ErrText, Lang)} + end; + #xdata{} -> + Txt = <<"Incorrect data form">>, + {error, xmpp:err_bad_request(Txt, Lang)}; + _ when is_binary(Nick), Nick /= <<"">> -> + iq_set_register_info(ServerHost, Host, From, Nick, Lang); + _ -> + ErrText = <<"You must fill in field \"Nickname\" in the form">>, + {error, xmpp:err_not_acceptable(ErrText, 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), +iq_set_register_info(ServerHost, Host, From, Nick, + Lang) -> + case iq_set_register_info2(ServerHost, Host, From, Nick, Lang) of + {atomic, ok} -> {result, undefined}; + {atomic, false} -> + ErrText = <<"That nickname is registered by another " + "person">>, + {error, xmpp:err_conflict(ErrText, Lang)}; + _ -> + Txt = <<"Database failure">>, + {error, xmpp:err_internal_server_error(Txt, Lang)} + end. + +iq_set_register_info2(ServerHost, Host, From, Icon, Lang) -> + LServer = jid:nameprep(ServerHost), + %% RidUrl2 = get_rid_final_value(RidUrl, LUS), + LUS = {From#jid.luser, From#jid.lserver}, WP = #webpresence{us = LUS, - jidurl = JidUrl, - ridurl = RidUrl2, - xml = XML, - avatar = Avatar, - js = JS, - text = Text, + jidurl = true, + ridurl = false, + xml = true, + avatar = false, + js = true, + text = true, icon = Icon}, F = fun() -> mnesia:write(WP) end, case mnesia:transaction(F) of {atomic, ok} -> + BaseURL = get_baseurl(ServerHost), send_message_registered(WP, From, Host, BaseURL, Lang), - {result, []}; + {atomic, ok}; _ -> - {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 -> - 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_binary(H) -> - H + {error, xmpp:err_internal_server_error()} end. send_message_registered(WP, To, Host, BaseURL, Lang) -> @@ -536,74 +529,14 @@ send_headline(Host, To, Subject, Body) -> ] }). -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) -> - #xmlel{name = _, attrs = _, children = Els} = SubEl, - case fxml: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 - end; - _ -> unregister_webpresence(From, Host, Lang) - end. - -process_iq_register_set2(From, Els, Host, BaseURL, Lang) -> - [ - #xmlel{ - name = <<"x">>, - attrs = _Attrs1, - children = _Els1 - } = XEl - ] = fxml:remove_cdata(Els), - case {fxml:get_tag_attr_s(<<"xmlns">>, XEl), fxml:get_tag_attr_s(<<"type">>, XEl)} of - {?NS_XDATA, <<"cancel">>} -> - {result, []}; - {?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, <<"---">>), - 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), + remove_user(From#jid.luser, From#jid.lserver), send_message_unregistered(From, Host, Lang), - {result, []}. + {result, undefined}. remove_user(User, Server) -> mnesia:dirty_delete(webpresence, {User, Server}). -iq_get_vcard() -> - [ - #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 @@ -625,10 +558,10 @@ try_auto_webpresence(LUser, LServer) -> ridurl = false, jidurl = true, xml = true, - avatar = true, + avatar = false, js = true, text = true, - icon = <<"jsf-jabber-text">>} + icon = "jsf-jabber-text"} end. get_status_weight(Show) -> @@ -641,12 +574,12 @@ get_status_weight(Show) -> _ -> 9 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}. +session_to_presence(#session{sid = {_, Pid}}) -> + P = ejabberd_c2s:get_presence(Pid), + #presence2{resource = (P#presence.from)#jid.resource, + show = misc:atom_to_binary(P#presence.show), + priority = P#presence.priority, + status = xmpp:get_text(P#presence.status)}. get_presences({bare, LUser, LServer}) -> [session_to_presence(Session) || @@ -656,12 +589,12 @@ 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), + A#presence2.priority == B#presence2.priority -> + WA = get_status_weight(A#presence2.show), + WB = get_status_weight(B#presence2.show), WA < WB; true -> - A#presence.priority > B#presence.priority + A#presence2.priority > B#presence2.priority end end, get_presences({bare, LUser, LServer})); @@ -678,11 +611,11 @@ get_presences({xml, LUser, LServer, Show_us}) -> #xmlel{ name = <<"resource">>, attrs = [ - {<<"name">>, Presence#presence.resource}, - {<<"show">>, Presence#presence.show}, - {<<"priority">>, iolist_to_binary(integer_to_list(Presence#presence.priority))} + {<<"name">>, Presence#presence2.resource}, + {<<"show">>, Presence#presence2.show}, + {<<"priority">>, iolist_to_binary(integer_to_list(Presence#presence2.priority))} ], - children = [{xmlcdata, Presence#presence.status}] + children = [{xmlcdata, Presence#presence2.status}] } end, get_presences({sorted, LUser, LServer}) @@ -694,13 +627,13 @@ get_presences({status, LUser, LServer, LResource}) -> [] -> <<"unavailable">>; Rs -> {value, R} = lists:keysearch(LResource, 2, Rs), - R#presence.show %% TODO why was this "status"?! + R#presence2.status end; get_presences({status, LUser, LServer}) -> case get_presences({sorted, LUser, LServer}) of [Highest | _Rest] -> - Highest#presence.show; %% TODO why was this "status"?! + Highest#presence2.status; _ -> <<"unavailable">> end; @@ -710,13 +643,13 @@ get_presences({show, LUser, LServer, LResource}) -> [] -> <<"unavailable">>; Rs -> {value, R} = lists:keysearch(LResource, 2, Rs), - R#presence.show + R#presence2.show end; get_presences({show, LUser, LServer}) -> case get_presences({sorted, LUser, LServer}) of [Highest | _Rest] -> - Highest#presence.show; + Highest#presence2.show; _ -> <<"unavailable">> end. @@ -744,12 +677,12 @@ make_js(WP, Prs, Show_us, Lang, Q) -> <<"}">>])]; _ -> lists:map( fun(Pr) -> - Show = Pr#presence.show, - ?BC([<<"{name:'">>, Pr#presence.resource, <<"',\n">>, - <<" priority:">>, intund2string(Pr#presence.priority), <<",\n">>, + Show = Pr#presence2.show, + ?BC([<<"{name:'">>, Pr#presence2.resource, <<"',\n">>, + <<" priority:">>, intund2string(Pr#presence2.priority), <<",\n">>, <<" show:'">>, Show, <<"',\n">>, <<" long_show:'">>, long_show(Show, Lang), <<"',\n">>, - <<" status:'">>, escape(Pr#presence.status), <<"',\n">>, + <<" status:'">>, escape(Pr#presence2.status), <<"',\n">>, FunImage(WP#webpresence.icon, Show), <<"}">>]) end, @@ -785,11 +718,8 @@ escape(S1) -> re:replace(S2, "\n", "\\n", [global, {return, list}]). get_baseurl(Host) -> - Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - Proc ! {tell_baseurl, self()}, - receive - {baseurl_is, BaseURL} -> BaseURL - end. + BaseURL1 = gen_mod:get_module_opt(Host, ?MODULE, baseurl), + ejabberd_regexp:greplace(BaseURL1, <<"@HOST@">>, Host). -define(XML_HEADER, <<"">>). @@ -878,9 +808,9 @@ 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, <<"">>), - IQ = #iq{type = get, xmlns = ?NS_VCARD}, + IQ = #iq{type = get}, %%+++++, xmlns = ?NS_VCARD}, IQr = Module:Function(JID, JID, IQ), - [VCard] = IQr#iq.sub_el, + [VCard] = ok, %%+++++ IQr#iq.sub_el, Mime = fxml:get_path_s(VCard, [{elem, <<"PHOTO">>}, {elem, <<"TYPE">>}, cdata]), BinVal = fxml:get_path_s(VCard, [{elem, <<"PHOTO">>}, {elem, <<"BINVAL">>}, cdata]), Photo = jlib:decode_base64(BinVal),