./ct_report/coverage/adhoc.COVER.html

1 %%%----------------------------------------------------------------------
2 %%% File : adhoc.erl
3 %%% Author : Magnus Henoch <henoch@dtek.chalmers.se>
4 %%% Purpose : Provide helper functions for ad-hoc commands (XEP-0050)
5 %%% Created : 31 Oct 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
26 -module(adhoc).
27 -author('henoch@dtek.chalmers.se').
28 -xep([{xep, 50}, {version, "1.3.0"}]).
29 -export([parse_request/1,
30 produce_response/2,
31 produce_response/4,
32 produce_response/1]).
33
34 -include("mongoose.hrl").
35 -include("jlib.hrl").
36 -include("adhoc.hrl").
37
38 -type request() :: #adhoc_request{}.
39 -type response() :: #adhoc_response{}.
40
41 -export_type([request/0, response/0]).
42
43 %% @doc Parse an ad-hoc request. Return either an adhoc_request record or
44 %% an {error, ErrorType} tuple.
45 -spec parse_request(jlib:iq()) -> request() | {error, exml:element()}.
46 parse_request(#iq{type = set, lang = Lang, sub_el = SubEl, xmlns = ?NS_COMMANDS}) ->
47 7 ?LOG_DEBUG(#{what => adhoc_parse_request,
48 text => <<"entering parse_request...">>,
49 7 sub_el => SubEl}),
50 7 Node = xml:get_tag_attr_s(<<"node">>, SubEl),
51 7 SessionID = xml:get_tag_attr_s(<<"sessionid">>, SubEl),
52 7 Action = xml:get_tag_attr_s(<<"action">>, SubEl),
53 7 XData = mongoose_data_forms:find_form(SubEl, false),
54 7 #xmlel{children = AllEls} = SubEl,
55 7 Others = case XData of
56 false ->
57 3 AllEls;
58 _ ->
59 4 lists:delete(XData, AllEls)
60 end,
61
62 7 #adhoc_request{lang = Lang,
63 node = Node,
64 session_id = SessionID,
65 action = Action,
66 xdata = XData,
67 others = Others};
68 parse_request(_) ->
69
:-(
{error, mongoose_xmpp_errors:bad_request()}.
70
71 %% @doc Produce a <command/> node to use as response from an adhoc_response
72 %% record, filling in values for language, node and session id from
73 %% the request.
74 -spec produce_response(request(), response() | atom()) -> #xmlel{}.
75 produce_response(Request, Status) when is_atom(Status) ->
76 2 produce_response(Request, Status, <<>>, []);
77 produce_response(#adhoc_request{lang = Lang,
78 node = Node,
79 session_id = SessionID},
80 Response) ->
81
:-(
produce_response(Response#adhoc_response{lang = Lang,
82 node = Node,
83 session_id = SessionID}).
84
85 %% @doc Produce a <command/> node to use as response from an adhoc_response
86 %% record, filling in values for language, node and session id from
87 %% the request.
88 -spec produce_response(request(), Status :: atom(), DefaultAction :: binary(),
89 Elements :: [exml:element()]) -> exml:element().
90 produce_response(Request, Status, DefaultAction, Elements) ->
91 4 #adhoc_request{lang = Lang, node = Node, session_id = SessionID} = Request,
92 4 produce_response(#adhoc_response{lang = Lang, node = Node, session_id = SessionID,
93 status = Status, default_action = DefaultAction,
94 elements = Elements}).
95
96
97 %% @doc Produce a <command/> node to use as response from an adhoc_response
98 %% record.
99 -spec produce_response(response()) -> exml:element().
100 produce_response(#adhoc_response{lang = _Lang,
101 node = Node,
102 session_id = ProvidedSessionID,
103 status = Status,
104 default_action = DefaultAction,
105 actions = Actions,
106 notes = Notes,
107 elements = Elements}) ->
108 5 SessionID = ensure_correct_session_id(ProvidedSessionID),
109 5 ActionsEls = maybe_actions_element(Actions, DefaultAction),
110 5 NotesEls = lists:map(fun note_to_xmlel/1, Notes),
111 5 #xmlel{name = <<"command">>,
112 attrs = [{<<"xmlns">>, ?NS_COMMANDS},
113 {<<"sessionid">>, SessionID},
114 {<<"node">>, Node},
115 {<<"status">>, list_to_binary(atom_to_list(Status))}],
116 children = ActionsEls ++ NotesEls ++ Elements}.
117
118 -spec ensure_correct_session_id(binary()) -> binary().
119 ensure_correct_session_id(SessionID) when is_binary(SessionID), SessionID /= <<>> ->
120
:-(
SessionID;
121 ensure_correct_session_id(_) ->
122 5 USec = os:system_time(microsecond),
123 5 TS = calendar:system_time_to_rfc3339(USec, [{offset, "Z"}, {unit, microsecond}]),
124 5 list_to_binary(TS).
125
126 -spec maybe_actions_element([binary()], binary()) -> [exml:element()].
127 maybe_actions_element([], _DefaultAction) ->
128 5 [];
129 maybe_actions_element(Actions, <<>>) ->
130 % If the "execute" attribute is absent, it defaults to "next".
131
:-(
AllActions = ensure_default_action_present(Actions, <<"next">>),
132
:-(
[#xmlel{
133 name = <<"actions">>,
134
:-(
children = [#xmlel{name = Action} || Action <- AllActions]
135 }];
136 maybe_actions_element(Actions, DefaultAction) ->
137 % A form which has an <actions/> element and an "execute" attribute
138 % which evaluates to an action which is not allowed is invalid.
139
:-(
AllActions = ensure_default_action_present(Actions, DefaultAction),
140
:-(
[#xmlel{
141 name = <<"actions">>,
142 attrs = [{<<"execute">>, DefaultAction}],
143
:-(
children = [#xmlel{name = Action} || Action <- AllActions]
144 }].
145
146 -spec ensure_default_action_present([binary()], binary()) -> [binary()].
147 ensure_default_action_present(Actions, DefaultAction) ->
148
:-(
case lists:member(DefaultAction, Actions) of
149
:-(
true -> Actions;
150
:-(
false -> [DefaultAction | Actions]
151 end.
152
153 -spec note_to_xmlel({binary(), iodata()}) -> exml:element().
154 note_to_xmlel({Type, Text}) ->
155 1 #xmlel{
156 name = <<"note">>,
157 attrs = [{<<"type">>, Type}],
158 children = [#xmlcdata{content = Text}]
159 }.
Line Hits Source