./ct_report/coverage/mod_adhoc.COVER.html

1 %%%----------------------------------------------------------------------
2 %%% File : mod_adhoc.erl
3 %%% Author : Magnus Henoch <henoch@dtek.chalmers.se>
4 %%% Purpose : Handle incoming ad-doc requests (XEP-0050)
5 %%% Created : 15 Nov 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
6 %%%
7 %%%
8 %%% ejabberd, Copyright (C) 2002-2011 ProcessOne
9 %%%
10 %%% This program is free software; you can redistribute it and/or
11 %%% modify it under the terms of the GNU General Public License as
12 %%% published by the Free Software Foundation; either version 2 of the
13 %%% License, or (at your option) any later version.
14 %%%
15 %%% This program is distributed in the hope that it will be useful,
16 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
17 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 %%% General Public License for more details.
19 %%%
20 %%% You should have received a copy of the GNU General Public License
21 %%% along with this program; if not, write to the Free Software
22 %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 %%%
24 %%%----------------------------------------------------------------------
25 -module(mod_adhoc).
26 -author('henoch@dtek.chalmers.se').
27
28 -behaviour(gen_mod).
29 -behaviour(mongoose_module_metrics).
30
31 -type command_hook_acc() :: {error, exml:element()} | exml:element() | ignore | empty.
32 -export_type([command_hook_acc/0]).
33
34 %% Gen_mod callbacks
35 -export([start/2,
36 stop/1,
37 config_spec/0,
38 supported_features/0]).
39
40 %% IQ and hook handlers
41 -export([process_local_iq/5,
42 process_sm_iq/5,
43 disco_local_items/1,
44 disco_local_identity/1,
45 disco_local_features/1,
46 disco_sm_items/1,
47 disco_sm_identity/1,
48 disco_sm_features/1,
49 ping_command/4]).
50
51 -ignore_xref([disco_local_features/1, disco_local_identity/1, disco_local_items/1,
52 disco_sm_features/1, disco_sm_identity/1, disco_sm_items/1,
53 ping_command/4, process_local_iq/5, process_sm_iq/5]).
54
55 -include("mongoose.hrl").
56 -include("jlib.hrl").
57 -include("adhoc.hrl").
58 -include("mongoose_config_spec.hrl").
59
60 -spec start(mongooseim:host_type(), gen_mod:module_opts()) -> ok.
61 start(HostType, #{iqdisc := IQDisc}) ->
62 318 [gen_iq_handler:add_iq_handler_for_domain(HostType, ?NS_COMMANDS, Component, Fn, #{}, IQDisc) ||
63 318 {Component, Fn} <- iq_handlers()],
64 318 ejabberd_hooks:add(hooks(HostType)).
65
66 -spec stop(mongooseim:host_type()) -> ok.
67 stop(HostType) ->
68 318 ejabberd_hooks:delete(hooks(HostType)),
69 318 [gen_iq_handler:remove_iq_handler_for_domain(HostType, ?NS_COMMANDS, Component) ||
70 318 {Component, _Fn} <- iq_handlers()],
71 318 ok.
72
73 iq_handlers() ->
74 636 [{ejabberd_local, fun ?MODULE:process_local_iq/5},
75 {ejabberd_sm, fun ?MODULE:process_sm_iq/5}].
76
77 hooks(HostType) ->
78 636 [{disco_local_identity, HostType, ?MODULE, disco_local_identity, 99},
79 {disco_local_features, HostType, ?MODULE, disco_local_features, 99},
80 {disco_local_items, HostType, ?MODULE, disco_local_items, 99},
81 {disco_sm_identity, HostType, ?MODULE, disco_sm_identity, 99},
82 {disco_sm_features, HostType, ?MODULE, disco_sm_features, 99},
83 {disco_sm_items, HostType, ?MODULE, disco_sm_items, 99},
84 {adhoc_local_commands, HostType, ?MODULE, ping_command, 100}].
85
86 %%%
87 %%% config_spec
88 %%%
89
90 -spec config_spec() -> mongoose_config_spec:config_section().
91 config_spec() ->
92 164 #section{
93 items = #{<<"report_commands_node">> => #option{type = boolean},
94 <<"iqdisc">> => mongoose_config_spec:iqdisc()},
95 defaults = #{<<"report_commands_node">> => false,
96 <<"iqdisc">> => one_queue},
97 format_items = map
98 }.
99
100 -spec supported_features() -> [atom()].
101 146 supported_features() -> [dynamic_domains].
102
103 %%%
104 %%% IQ handlers
105 %%%
106
107 -spec process_local_iq(mongoose_acc:t(), jid:jid(), jid:jid(), jlib:iq(), map())
108 -> {mongoose_acc:t(), ignore | jlib:iq()}.
109 process_local_iq(Acc, From, To, IQ, _Extra) ->
110 1 {Acc, process_adhoc_request(Acc, From, To, IQ, adhoc_local_commands)}.
111
112 -spec process_sm_iq(mongoose_acc:t(), jid:jid(), jid:jid(), jlib:iq(), map()) ->
113 {mongoose_acc:t(), ignore | jlib:iq()}.
114 process_sm_iq(Acc, From, To, IQ, _Extra) ->
115
:-(
{Acc, process_adhoc_request(Acc, From, To, IQ, adhoc_sm_commands)}.
116
117 -spec process_adhoc_request(mongoose_acc:t(), jid:jid(), jid:jid(), jlib:iq(),
118 Hook :: atom()) -> ignore | jlib:iq().
119 process_adhoc_request(Acc, From, To, #iq{sub_el = SubEl} = IQ, Hook) ->
120 1 ?LOG_DEBUG(#{what => adhoc_parse_request, iq => IQ, hook => Hook}),
121 1 case adhoc:parse_request(IQ) of
122 {error, Error} ->
123
:-(
IQ#iq{type = error, sub_el = [SubEl, Error]};
124 #adhoc_request{} = AdhocRequest ->
125 1 HostType = mongoose_acc:host_type(Acc),
126 1 case run_request_hook(Hook, HostType, From, To, AdhocRequest) of
127 ignore ->
128
:-(
ignore;
129 empty ->
130
:-(
IQ#iq{type = error, sub_el = [SubEl, mongoose_xmpp_errors:item_not_found()]};
131 {error, Error} ->
132
:-(
IQ#iq{type = error, sub_el = [SubEl, Error]};
133 Command ->
134 1 IQ#iq{type = result, sub_el = [Command]}
135 end
136 end.
137
138 run_request_hook(adhoc_local_commands, HostType, From, To, AdhocRequest) ->
139 1 mongoose_hooks:adhoc_local_commands(HostType, From, To, AdhocRequest);
140 run_request_hook(adhoc_sm_commands, HostType, From, To, AdhocRequest) ->
141
:-(
mongoose_hooks:adhoc_sm_commands(HostType, From, To, AdhocRequest).
142
143 %%%
144 %%% Hooks handlers
145 %%%
146
147 -spec disco_local_items(mongoose_disco:item_acc()) -> mongoose_disco:item_acc().
148 disco_local_items(Acc = #{host_type := HostType, to_jid := #jid{lserver = LServer}, node := <<>>, lang := Lang}) ->
149 29 Items = case are_commands_visible(HostType) of
150 false ->
151 28 [];
152 _ ->
153 1 [item(LServer, ?NS_COMMANDS, <<"Commands">>, Lang)]
154 end,
155 29 mongoose_disco:add_items(Items, Acc);
156 disco_local_items(Acc = #{to_jid := #jid{lserver = LServer}, node := ?NS_COMMANDS, lang := Lang}) ->
157 2 Items = [item(LServer, <<"ping">>, <<"Ping">>, Lang)],
158 2 mongoose_disco:add_items(Items, Acc);
159 disco_local_items(Acc = #{node := <<"ping">>}) ->
160
:-(
Acc#{result := []}; % override the result
161 disco_local_items(Acc) ->
162
:-(
Acc.
163
164 %%-------------------------------------------------------------------------
165
166 -spec disco_sm_items(mongoose_disco:item_acc()) -> mongoose_disco:item_acc().
167 disco_sm_items(Acc = #{host_type := HostType, to_jid := To, node := <<>>, lang := Lang}) ->
168 6 Items = case are_commands_visible(HostType) of
169 false ->
170 5 [];
171 _ ->
172 1 [item(jid:to_binary(To), ?NS_COMMANDS, <<"Commands">>, Lang)]
173 end,
174 6 mongoose_disco:add_items(Items, Acc);
175 disco_sm_items(Acc) ->
176 4 Acc.
177
178 are_commands_visible(HostType) ->
179 35 gen_mod:get_module_opt(HostType, ?MODULE, report_commands_node).
180
181 item(LServer, Node, Name, Lang) ->
182 4 #{jid => LServer, node => Node, name => translate:translate(Lang, Name)}.
183
184 %%-------------------------------------------------------------------------
185
186 %% @doc On disco info request to the ad-hoc node, return automation/command-list.
187 -spec disco_local_identity(mongoose_disco:identity_acc()) -> mongoose_disco:identity_acc().
188 disco_local_identity(Acc = #{node := ?NS_COMMANDS, lang := Lang}) ->
189 2 mongoose_disco:add_identities([command_list_identity(Lang)], Acc);
190 disco_local_identity(Acc = #{node := <<"ping">>, lang := Lang}) ->
191 2 mongoose_disco:add_identities([ping_identity(Lang)], Acc);
192 disco_local_identity(Acc) ->
193 155 Acc.
194
195 %%-------------------------------------------------------------------------
196
197 %% @doc On disco info request to the ad-hoc node, return automation/command-list.
198 -spec disco_sm_identity(mongoose_disco:identity_acc()) -> mongoose_disco:identity_acc().
199 disco_sm_identity(Acc = #{node := ?NS_COMMANDS, lang := Lang}) ->
200 2 mongoose_disco:add_identities([command_list_identity(Lang)], Acc);
201 disco_sm_identity(Acc) ->
202 9 Acc.
203
204 ping_identity(Lang) ->
205 2 #{category => <<"automation">>,
206 type => <<"command-node">>,
207 name => translate:translate(Lang, <<"Ping">>)}.
208
209 command_list_identity(Lang) ->
210 4 #{category => <<"automation">>,
211 type => <<"command-list">>,
212 name => translate:translate(Lang, <<"Commands">>)}.
213
214 %%-------------------------------------------------------------------------
215
216 -spec disco_local_features(mongoose_disco:feature_acc()) -> mongoose_disco:feature_acc().
217 disco_local_features(Acc = #{node := <<>>}) ->
218 154 mongoose_disco:add_features([?NS_COMMANDS], Acc);
219 disco_local_features(Acc = #{node := ?NS_COMMANDS}) ->
220 %% override all lesser features...
221 2 Acc#{result := []};
222 disco_local_features(Acc = #{node := <<"ping">>}) ->
223 %% override all lesser features...
224 2 Acc#{result := [?NS_COMMANDS]};
225 disco_local_features(Acc) ->
226 1 Acc.
227
228 %%-------------------------------------------------------------------------
229
230 -spec disco_sm_features(mongoose_disco:feature_acc()) -> mongoose_disco:feature_acc().
231 disco_sm_features(Acc = #{node := <<>>}) ->
232 9 mongoose_disco:add_features([?NS_COMMANDS], Acc);
233 disco_sm_features(Acc = #{node := ?NS_COMMANDS}) ->
234 %% override all lesser features...
235 2 Acc#{result := []};
236 disco_sm_features(Acc) ->
237
:-(
Acc.
238
239 %%-------------------------------------------------------------------------
240
241 -spec ping_command(Acc :: command_hook_acc(),
242 From :: jid:jid(),
243 To :: jid:jid(),
244 adhoc:request()) -> command_hook_acc().
245 ping_command(empty, _From, _To,
246 #adhoc_request{lang = Lang,
247 node = <<"ping">> = Node,
248 session_id = SessionID,
249 action = Action}) ->
250 1 case Action == <<"">> orelse Action == <<"execute">> of
251 true ->
252 1 adhoc:produce_response(
253 #adhoc_response{lang = Lang,
254 node = Node,
255 session_id = SessionID,
256 status = completed,
257 notes = [{<<"info">>, translate:translate(Lang, <<"Pong">>)}]});
258 false ->
259
:-(
{error, mongoose_xmpp_errors:bad_request()}
260 end;
261 ping_command(Acc, _From, _To, _Request) ->
262
:-(
Acc.
263
Line Hits Source