channels: Allow updating variable value
[asterisk/asterisk.git] / res / ari / resource_endpoints.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012 - 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief /api-docs/endpoints.{format} implementation- Endpoint resources
22  *
23  * \author David M. Lee, II <dlee@digium.com>
24  */
25
26 #include "asterisk.h"
27
28 #include "resource_endpoints.h"
29
30 #include "asterisk/astobj2.h"
31 #include "asterisk/stasis.h"
32 #include "asterisk/stasis_app.h"
33 #include "asterisk/stasis_endpoints.h"
34 #include "asterisk/channel.h"
35 #include "asterisk/message.h"
36
37 void ast_ari_endpoints_list(struct ast_variable *headers,
38         struct ast_ari_endpoints_list_args *args,
39         struct ast_ari_response *response)
40 {
41         RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
42         RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
43         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
44         struct ao2_iterator i;
45         void *obj;
46
47         cache = ast_endpoint_cache();
48         if (!cache) {
49                 ast_ari_response_error(
50                         response, 500, "Internal Server Error",
51                         "Message bus not initialized");
52                 return;
53         }
54         ao2_ref(cache, +1);
55
56         snapshots = stasis_cache_dump(cache, ast_endpoint_snapshot_type());
57         if (!snapshots) {
58                 ast_ari_response_alloc_failed(response);
59                 return;
60         }
61
62         json = ast_json_array_create();
63         if (!json) {
64                 ast_ari_response_alloc_failed(response);
65                 return;
66         }
67
68         i = ao2_iterator_init(snapshots, 0);
69         while ((obj = ao2_iterator_next(&i))) {
70                 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
71                 struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
72                 struct ast_json *json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
73
74                 if (!json_endpoint || ast_json_array_append(json, json_endpoint)) {
75                         ao2_iterator_destroy(&i);
76                         ast_ari_response_alloc_failed(response);
77                         return;
78                 }
79         }
80         ao2_iterator_destroy(&i);
81
82         ast_ari_response_ok(response, ast_json_ref(json));
83 }
84
85 void ast_ari_endpoints_list_by_tech(struct ast_variable *headers,
86         struct ast_ari_endpoints_list_by_tech_args *args,
87         struct ast_ari_response *response)
88 {
89         RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
90         RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
91         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
92         struct ast_endpoint *tech_endpoint;
93         struct ao2_iterator i;
94         void *obj;
95
96         tech_endpoint = ast_endpoint_find_by_id(args->tech);
97         if (!tech_endpoint) {
98                 ast_ari_response_error(response, 404, "Not Found",
99                                        "No Endpoints found - invalid tech %s", args->tech);
100                 return;
101         }
102         ao2_ref(tech_endpoint, -1);
103
104         cache = ast_endpoint_cache();
105         if (!cache) {
106                 ast_ari_response_error(
107                         response, 500, "Internal Server Error",
108                         "Message bus not initialized");
109                 return;
110         }
111         ao2_ref(cache, +1);
112
113         snapshots = stasis_cache_dump(cache, ast_endpoint_snapshot_type());
114         if (!snapshots) {
115                 ast_ari_response_alloc_failed(response);
116                 return;
117         }
118
119         json = ast_json_array_create();
120         if (!json) {
121                 ast_ari_response_alloc_failed(response);
122                 return;
123         }
124
125         i = ao2_iterator_init(snapshots, 0);
126         while ((obj = ao2_iterator_next(&i))) {
127                 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
128                 struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
129                 struct ast_json *json_endpoint;
130                 int r;
131
132                 if (strcasecmp(args->tech, snapshot->tech) != 0) {
133                         continue;
134                 }
135
136                 json_endpoint = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
137                 if (!json_endpoint) {
138                         continue;
139                 }
140
141                 r = ast_json_array_append(
142                         json, json_endpoint);
143                 if (r != 0) {
144                         ao2_iterator_destroy(&i);
145                         ast_ari_response_alloc_failed(response);
146                         return;
147                 }
148         }
149         ao2_iterator_destroy(&i);
150         ast_ari_response_ok(response, ast_json_ref(json));
151 }
152
153 void ast_ari_endpoints_get(struct ast_variable *headers,
154         struct ast_ari_endpoints_get_args *args,
155         struct ast_ari_response *response)
156 {
157         struct ast_json *json;
158         RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
159
160         snapshot = ast_endpoint_latest_snapshot(args->tech, args->resource);
161         if (!snapshot) {
162                 ast_ari_response_error(response, 404, "Not Found",
163                         "Endpoint not found");
164                 return;
165         }
166
167         json = ast_endpoint_snapshot_to_json(snapshot, stasis_app_get_sanitizer());
168         if (!json) {
169                 ast_ari_response_alloc_failed(response);
170                 return;
171         }
172
173         ast_ari_response_ok(response, json);
174 }
175
176 static void send_message(const char *to, const char *from, const char *body, struct ast_variable *variables, struct ast_ari_response *response)
177 {
178         struct ast_variable *current;
179         struct ast_msg *msg;
180         int res = 0;
181
182         if (ast_strlen_zero(to)) {
183                 ast_ari_response_error(response, 400, "Bad Request",
184                         "To must be specified");
185                 return;
186         }
187
188         msg = ast_msg_alloc();
189         if (!msg) {
190                 ast_ari_response_alloc_failed(response);
191                 return;
192         }
193
194         res |= ast_msg_set_from(msg, "%s", from);
195         res |= ast_msg_set_to(msg, "%s", to);
196
197         if (!ast_strlen_zero(body)) {
198                 res |= ast_msg_set_body(msg, "%s", body);
199         }
200
201         for (current = variables; current; current = current->next) {
202                 res |= ast_msg_set_var_outbound(msg, current->name, current->value);
203         }
204
205         if (res) {
206                 ast_ari_response_alloc_failed(response);
207                 ast_msg_destroy(msg);
208                 return;
209         }
210
211         if (ast_msg_send(msg, to, from)) {
212                 ast_ari_response_error(response, 404, "Not Found",
213                         "Endpoint not found");
214         }
215
216         response->message = ast_json_null();
217         response->response_code = 202;
218         response->response_text = "Accepted";
219 }
220
221 /*!
222  * \internal
223  * \brief Convert a \c ast_json list of key/value pair tuples into a \c ast_variable list
224  * \since 13.3.0
225  *
226  * \param[out] response HTTP response if error
227  * \param json_variables The JSON blob containing the variable
228  * \param[out] variables An out reference to the variables to populate.
229  *
230  * \retval 0 on success.
231  * \retval -1 on error.
232  */
233 static int json_to_ast_variables(struct ast_ari_response *response, struct ast_json *json_variables, struct ast_variable **variables)
234 {
235         enum ast_json_to_ast_vars_code res;
236
237         res = ast_json_to_ast_variables(json_variables, variables);
238         switch (res) {
239         case AST_JSON_TO_AST_VARS_CODE_SUCCESS:
240                 return 0;
241         case AST_JSON_TO_AST_VARS_CODE_INVALID_TYPE:
242                 ast_ari_response_error(response, 400, "Bad Request",
243                         "Only string values in the 'variables' object allowed");
244                 break;
245         case AST_JSON_TO_AST_VARS_CODE_OOM:
246                 ast_ari_response_alloc_failed(response);
247                 break;
248         }
249         ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to Asterisk variables\n");
250
251         return -1;
252 }
253
254 void ast_ari_endpoints_send_message(struct ast_variable *headers,
255         struct ast_ari_endpoints_send_message_args *args,
256         struct ast_ari_response *response)
257 {
258         struct ast_variable *variables = NULL;
259
260         if (args->variables) {
261                 struct ast_json *json_variables;
262
263                 ast_ari_endpoints_send_message_parse_body(args->variables, args);
264                 json_variables = ast_json_object_get(args->variables, "variables");
265                 if (json_variables
266                         && json_to_ast_variables(response, json_variables, &variables)) {
267                         return;
268                 }
269         }
270
271         send_message(args->to, args->from, args->body, variables, response);
272         ast_variables_destroy(variables);
273 }
274
275 void ast_ari_endpoints_send_message_to_endpoint(struct ast_variable *headers,
276         struct ast_ari_endpoints_send_message_to_endpoint_args *args,
277         struct ast_ari_response *response)
278 {
279         struct ast_variable *variables = NULL;
280         struct ast_endpoint_snapshot *snapshot;
281         char msg_to[128];
282         char *tech = ast_strdupa(args->tech);
283
284         /* Really, we just want to know if this thing exists */
285         snapshot = ast_endpoint_latest_snapshot(args->tech, args->resource);
286         if (!snapshot) {
287                 ast_ari_response_error(response, 404, "Not Found",
288                         "Endpoint not found");
289                 return;
290         }
291         ao2_ref(snapshot, -1);
292
293         if (args->variables) {
294                 struct ast_json *json_variables;
295
296                 ast_ari_endpoints_send_message_to_endpoint_parse_body(args->variables, args);
297                 json_variables = ast_json_object_get(args->variables, "variables");
298                 if (json_variables
299                         && json_to_ast_variables(response, json_variables, &variables)) {
300                         return;
301                 }
302         }
303
304         snprintf(msg_to, sizeof(msg_to), "%s:%s", ast_str_to_lower(tech), args->resource);
305
306         send_message(msg_to, args->from, args->body, variables, response);
307         ast_variables_destroy(variables);
308 }