%%%---------------------------------------------------------------------- %%% File : mod_adhoc.erl %%% Author : Magnus Henoch %%% Purpose : Handle incoming ad-doc requests (JEP-0050) %%% Created : 15 Nov 2005 by Magnus Henoch %%% %%% %%% ejabberd, Copyright (C) 2002-2008 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as %%% published by the Free Software Foundation; either version 2 of the %%% License, or (at your option) any later version. %%% %%% This program is distributed in the hope that it will be useful, %%% but WITHOUT ANY WARRANTY; without even the implied warranty of %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU %%% General Public License for more details. %%% %%% You should have received a copy of the GNU General Public License %%% along with this program; if not, write to the Free Software %%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA %%% 02111-1307 USA %%% %%%---------------------------------------------------------------------- -module(mod_adhoc). -author('henoch@dtek.chalmers.se'). -behaviour(gen_mod). -export([start/2, stop/1, process_local_iq/3, process_sm_iq/3, get_local_commands/5, get_local_identity/5, get_local_features/5, get_sm_commands/5, get_sm_identity/5, get_sm_features/5, ping_item/4, ping_command/4]). -include_lib("exmpp/include/exmpp.hrl"). -include("ejabberd.hrl"). -include("adhoc.hrl"). start(Host, Opts) -> IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue), gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_ADHOC, ?MODULE, process_local_iq, IQDisc), gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_ADHOC, ?MODULE, process_sm_iq, IQDisc), ejabberd_hooks:add(disco_local_identity, Host, ?MODULE, get_local_identity, 99), ejabberd_hooks:add(disco_local_features, Host, ?MODULE, get_local_features, 99), ejabberd_hooks:add(disco_local_items, Host, ?MODULE, get_local_commands, 99), ejabberd_hooks:add(disco_sm_identity, Host, ?MODULE, get_sm_identity, 99), ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 99), ejabberd_hooks:add(disco_sm_items, Host, ?MODULE, get_sm_commands, 99), ejabberd_hooks:add(adhoc_local_items, Host, ?MODULE, ping_item, 100), ejabberd_hooks:add(adhoc_local_commands, Host, ?MODULE, ping_command, 100). stop(Host) -> ejabberd_hooks:delete(adhoc_local_commands, Host, ?MODULE, ping_command, 100), ejabberd_hooks:delete(adhoc_local_items, Host, ?MODULE, ping_item, 100), ejabberd_hooks:delete(disco_sm_items, Host, ?MODULE, get_sm_commands, 99), ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 99), ejabberd_hooks:delete(disco_sm_identity, Host, ?MODULE, get_sm_identity, 99), ejabberd_hooks:delete(disco_local_items, Host, ?MODULE, get_local_commands, 99), ejabberd_hooks:delete(disco_local_features, Host, ?MODULE, get_local_features, 99), ejabberd_hooks:delete(disco_local_identity, Host, ?MODULE, get_local_identity, 99), gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_ADHOC), gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_ADHOC). %------------------------------------------------------------------------- get_local_commands(Acc, _From, #jid{domain = Server, ldomain = LServer} = _To, "", Lang) -> Display = gen_mod:get_module_opt(LServer, ?MODULE, report_commands_node, false), case Display of false -> Acc; _ -> Items = case Acc of {result, I} -> I; _ -> [] end, Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [#xmlattr{name = 'jid', value = Server}, #xmlattr{name = 'node', value = ?NS_ADHOC_s}, #xmlattr{name = 'name', value = translate:translate(Lang, "Commands")}] }], {result, Items ++ Nodes} end; get_local_commands(_Acc, From, #jid{ldomain = LServer} = To, ?NS_ADHOC_s, Lang) -> % XXX OLD FORMAT: From, To. FromOld = jlib:to_old_jid(From), ToOld = jlib:to_old_jid(To), ejabberd_hooks:run_fold(adhoc_local_items, LServer, {result, []}, [FromOld, ToOld, Lang]); get_local_commands(_Acc, _From, _To, "ping", _Lang) -> {result, []}; get_local_commands(Acc, _From, _To, _Node, _Lang) -> Acc. %------------------------------------------------------------------------- get_sm_commands(Acc, _From, #jid{ldomain = LServer} = To, "", Lang) -> Display = gen_mod:get_module_opt(LServer, ?MODULE, report_commands_node, false), case Display of false -> Acc; _ -> Items = case Acc of {result, I} -> I; _ -> [] end, Nodes = [#xmlel{ns = ?NS_DISCO_ITEMS, name = 'item', attrs = [#xmlattr{name = 'jid', value = exmpp_jid:jid_to_list(To)}, #xmlattr{name = 'node', value = ?NS_ADHOC_s}, #xmlattr{name = 'name', value = translate:translate(Lang, "Commands")}] }], {result, Items ++ Nodes} end; get_sm_commands(_Acc, From, #jid{ldomain = LServer} = To, ?NS_ADHOC_s, Lang) -> % XXX OLD FORMAT: From, To. FromOld = jlib:to_old_jid(From), ToOld = jlib:to_old_jid(To), ejabberd_hooks:run_fold(adhoc_sm_items, LServer, {result, []}, [FromOld, ToOld, Lang]); get_sm_commands(Acc, _From, _To, _Node, _Lang) -> Acc. %------------------------------------------------------------------------- %% On disco info request to the ad-hoc node, return automation/command-list. get_local_identity(Acc, _From, _To, ?NS_ADHOC_s, Lang) -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [#xmlattr{name = 'category', value = "automation"}, #xmlattr{name = 'type', value = "command-list"}, #xmlattr{name = 'name', value = translate:translate(Lang, "Commands")}]} | Acc]; get_local_identity(Acc, _From, _To, "ping", Lang) -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [#xmlattr{name = 'category', value = "automation"}, #xmlattr{name = 'type', value = "command-node"}, #xmlattr{name = 'name', value = translate:translate(Lang, "Ping")}]} | Acc]; get_local_identity(Acc, _From, _To, _Node, _Lang) -> Acc. %------------------------------------------------------------------------- %% On disco info request to the ad-hoc node, return automation/command-list. get_sm_identity(Acc, _From, _To, ?NS_ADHOC_s, Lang) -> [#xmlel{ns = ?NS_DISCO_INFO, name = 'identity', attrs = [#xmlattr{name = 'category', value = "automation"}, #xmlattr{name = 'type', value = "command-list"}, #xmlattr{name = 'name', value = translate:translate(Lang, "Commands")}]} | Acc]; get_sm_identity(Acc, _From, _To, _Node, _Lang) -> Acc. %------------------------------------------------------------------------- get_local_features(Acc, _From, _To, "", _Lang) -> Feats = case Acc of {result, I} -> I; _ -> [] end, {result, Feats ++ [?NS_ADHOC_s]}; get_local_features(_Acc, _From, _To, ?NS_ADHOC_s, _Lang) -> %% override all lesser features... {result, []}; get_local_features(_Acc, _From, _To, "ping", _Lang) -> %% override all lesser features... {result, [?NS_ADHOC_s]}; get_local_features(Acc, _From, _To, _Node, _Lang) -> Acc. %------------------------------------------------------------------------- get_sm_features(Acc, _From, _To, "", _Lang) -> Feats = case Acc of {result, I} -> I; _ -> [] end, {result, Feats ++ [?NS_ADHOC_s]}; get_sm_features(_Acc, _From, _To, ?NS_ADHOC_s, _Lang) -> %% override all lesser features... {result, []}; get_sm_features(Acc, _From, _To, _Node, _Lang) -> Acc. %------------------------------------------------------------------------- process_local_iq(From, To, IQ_Rec) -> process_adhoc_request(From, To, IQ_Rec, adhoc_local_commands). process_sm_iq(From, To, IQ_Rec) -> process_adhoc_request(From, To, IQ_Rec, adhoc_sm_commands). process_adhoc_request(From, To, IQ_Rec, Hook) -> ?DEBUG("About to parse ~p...", [IQ_Rec]), case adhoc:parse_request(IQ_Rec) of {error, Error} -> exmpp_iq:error(IQ_Rec, Error); #adhoc_request{} = AdhocRequest -> Host = To#jid.ldomain, % XXX OLD FORMAT: From, To. FromOld = jlib:to_old_jid(From), ToOld = jlib:to_old_jid(To), case ejabberd_hooks:run_fold(Hook, Host, empty, [FromOld, ToOld, AdhocRequest]) of ignore -> ignore; empty -> exmpp_iq:error(IQ_Rec, 'item-not-found'); {error, Error} -> exmpp_iq:error(IQ_Rec, Error); Command -> exmpp_iq:result(IQ_Rec, Command) end end. ping_item(Acc, _From, #jid{domain = Server} = _To, Lang) -> Items = case Acc of {result, I} -> I; _ -> [] end, Nodes = [#xmlel{ns = ?NS_DISCO_INFO, name = 'item', attrs = [#xmlattr{name = 'jid', value = Server}, #xmlattr{name = 'node', value = "ping"}, #xmlattr{name = 'name', value = translate:translate(Lang, "Ping")}]}], {result, Items ++ Nodes}. ping_command(_Acc, _From, _To, #adhoc_request{lang = Lang, node = "ping", sessionid = _Sessionid, action = Action} = Request) -> if Action == ""; Action == "execute" -> adhoc:produce_response( Request, #adhoc_response{status = completed, notes = [{"info", translate:translate( Lang, "Pong")}]}); true -> {error, 'bad-request'} end; ping_command(Acc, _From, _To, _Request) -> Acc.