Merge "res_pjsip: New endpoint option "refer_blind_progress""
[asterisk/asterisk.git] / res / res_ari_applications.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 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 /*
20  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
21  * !!!!!                               DO NOT EDIT                        !!!!!
22  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
23  * This file is generated by a mustache template. Please see the original
24  * template in rest-api-templates/res_ari_resource.c.mustache
25  */
26
27 /*! \file
28  *
29  * \brief Stasis application resources
30  *
31  * \author David M. Lee, II <dlee@digium.com>
32  */
33
34 /*** MODULEINFO
35         <depend type="module">res_ari</depend>
36         <depend type="module">res_ari_model</depend>
37         <depend type="module">res_stasis</depend>
38         <support_level>core</support_level>
39  ***/
40
41 #include "asterisk.h"
42
43 #include "asterisk/app.h"
44 #include "asterisk/module.h"
45 #include "asterisk/stasis_app.h"
46 #include "ari/resource_applications.h"
47 #if defined(AST_DEVMODE)
48 #include "ari/ari_model_validators.h"
49 #endif
50
51 #define MAX_VALS 128
52
53 /*!
54  * \brief Parameter parsing callback for /applications.
55  * \param get_params GET parameters in the HTTP request.
56  * \param path_vars Path variables extracted from the request.
57  * \param headers HTTP headers.
58  * \param[out] response Response to the HTTP request.
59  */
60 static void ast_ari_applications_list_cb(
61         struct ast_tcptls_session_instance *ser,
62         struct ast_variable *get_params, struct ast_variable *path_vars,
63         struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
64 {
65         struct ast_ari_applications_list_args args = {};
66 #if defined(AST_DEVMODE)
67         int is_valid;
68         int code;
69 #endif /* AST_DEVMODE */
70
71         ast_ari_applications_list(headers, &args, response);
72 #if defined(AST_DEVMODE)
73         code = response->response_code;
74
75         switch (code) {
76         case 0: /* Implementation is still a stub, or the code wasn't set */
77                 is_valid = response->message == NULL;
78                 break;
79         case 500: /* Internal Server Error */
80         case 501: /* Not Implemented */
81                 is_valid = 1;
82                 break;
83         default:
84                 if (200 <= code && code <= 299) {
85                         is_valid = ast_ari_validate_list(response->message,
86                                 ast_ari_validate_application_fn());
87                 } else {
88                         ast_log(LOG_ERROR, "Invalid error response %d for /applications\n", code);
89                         is_valid = 0;
90                 }
91         }
92
93         if (!is_valid) {
94                 ast_log(LOG_ERROR, "Response validation failed for /applications\n");
95                 ast_ari_response_error(response, 500,
96                         "Internal Server Error", "Response validation failed");
97         }
98 #endif /* AST_DEVMODE */
99
100 fin: __attribute__((unused))
101         return;
102 }
103 /*!
104  * \brief Parameter parsing callback for /applications/{applicationName}.
105  * \param get_params GET parameters in the HTTP request.
106  * \param path_vars Path variables extracted from the request.
107  * \param headers HTTP headers.
108  * \param[out] response Response to the HTTP request.
109  */
110 static void ast_ari_applications_get_cb(
111         struct ast_tcptls_session_instance *ser,
112         struct ast_variable *get_params, struct ast_variable *path_vars,
113         struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
114 {
115         struct ast_ari_applications_get_args args = {};
116         struct ast_variable *i;
117 #if defined(AST_DEVMODE)
118         int is_valid;
119         int code;
120 #endif /* AST_DEVMODE */
121
122         for (i = path_vars; i; i = i->next) {
123                 if (strcmp(i->name, "applicationName") == 0) {
124                         args.application_name = (i->value);
125                 } else
126                 {}
127         }
128         ast_ari_applications_get(headers, &args, response);
129 #if defined(AST_DEVMODE)
130         code = response->response_code;
131
132         switch (code) {
133         case 0: /* Implementation is still a stub, or the code wasn't set */
134                 is_valid = response->message == NULL;
135                 break;
136         case 500: /* Internal Server Error */
137         case 501: /* Not Implemented */
138         case 404: /* Application does not exist. */
139                 is_valid = 1;
140                 break;
141         default:
142                 if (200 <= code && code <= 299) {
143                         is_valid = ast_ari_validate_application(
144                                 response->message);
145                 } else {
146                         ast_log(LOG_ERROR, "Invalid error response %d for /applications/{applicationName}\n", code);
147                         is_valid = 0;
148                 }
149         }
150
151         if (!is_valid) {
152                 ast_log(LOG_ERROR, "Response validation failed for /applications/{applicationName}\n");
153                 ast_ari_response_error(response, 500,
154                         "Internal Server Error", "Response validation failed");
155         }
156 #endif /* AST_DEVMODE */
157
158 fin: __attribute__((unused))
159         return;
160 }
161 int ast_ari_applications_subscribe_parse_body(
162         struct ast_json *body,
163         struct ast_ari_applications_subscribe_args *args)
164 {
165         struct ast_json *field;
166         /* Parse query parameters out of it */
167         field = ast_json_object_get(body, "eventSource");
168         if (field) {
169                 /* If they were silly enough to both pass in a query param and a
170                  * JSON body, free up the query value.
171                  */
172                 ast_free(args->event_source);
173                 if (ast_json_typeof(field) == AST_JSON_ARRAY) {
174                         /* Multiple param passed as array */
175                         size_t i;
176                         args->event_source_count = ast_json_array_size(field);
177                         args->event_source = ast_malloc(sizeof(*args->event_source) * args->event_source_count);
178
179                         if (!args->event_source) {
180                                 return -1;
181                         }
182
183                         for (i = 0; i < args->event_source_count; ++i) {
184                                 args->event_source[i] = ast_json_string_get(ast_json_array_get(field, i));
185                         }
186                 } else {
187                         /* Multiple param passed as single value */
188                         args->event_source_count = 1;
189                         args->event_source = ast_malloc(sizeof(*args->event_source) * args->event_source_count);
190                         if (!args->event_source) {
191                                 return -1;
192                         }
193                         args->event_source[0] = ast_json_string_get(field);
194                 }
195         }
196         return 0;
197 }
198
199 /*!
200  * \brief Parameter parsing callback for /applications/{applicationName}/subscription.
201  * \param get_params GET parameters in the HTTP request.
202  * \param path_vars Path variables extracted from the request.
203  * \param headers HTTP headers.
204  * \param[out] response Response to the HTTP request.
205  */
206 static void ast_ari_applications_subscribe_cb(
207         struct ast_tcptls_session_instance *ser,
208         struct ast_variable *get_params, struct ast_variable *path_vars,
209         struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
210 {
211         struct ast_ari_applications_subscribe_args args = {};
212         struct ast_variable *i;
213 #if defined(AST_DEVMODE)
214         int is_valid;
215         int code;
216 #endif /* AST_DEVMODE */
217
218         for (i = get_params; i; i = i->next) {
219                 if (strcmp(i->name, "eventSource") == 0) {
220                         /* Parse comma separated list */
221                         char *vals[MAX_VALS];
222                         size_t j;
223
224                         args.event_source_parse = ast_strdup(i->value);
225                         if (!args.event_source_parse) {
226                                 ast_ari_response_alloc_failed(response);
227                                 goto fin;
228                         }
229
230                         if (strlen(args.event_source_parse) == 0) {
231                                 /* ast_app_separate_args can't handle "" */
232                                 args.event_source_count = 1;
233                                 vals[0] = args.event_source_parse;
234                         } else {
235                                 args.event_source_count = ast_app_separate_args(
236                                         args.event_source_parse, ',', vals,
237                                         ARRAY_LEN(vals));
238                         }
239
240                         if (args.event_source_count == 0) {
241                                 ast_ari_response_alloc_failed(response);
242                                 goto fin;
243                         }
244
245                         if (args.event_source_count >= MAX_VALS) {
246                                 ast_ari_response_error(response, 400,
247                                         "Bad Request",
248                                         "Too many values for event_source");
249                                 goto fin;
250                         }
251
252                         args.event_source = ast_malloc(sizeof(*args.event_source) * args.event_source_count);
253                         if (!args.event_source) {
254                                 ast_ari_response_alloc_failed(response);
255                                 goto fin;
256                         }
257
258                         for (j = 0; j < args.event_source_count; ++j) {
259                                 args.event_source[j] = (vals[j]);
260                         }
261                 } else
262                 {}
263         }
264         for (i = path_vars; i; i = i->next) {
265                 if (strcmp(i->name, "applicationName") == 0) {
266                         args.application_name = (i->value);
267                 } else
268                 {}
269         }
270         if (ast_ari_applications_subscribe_parse_body(body, &args)) {
271                 ast_ari_response_alloc_failed(response);
272                 goto fin;
273         }
274         ast_ari_applications_subscribe(headers, &args, response);
275 #if defined(AST_DEVMODE)
276         code = response->response_code;
277
278         switch (code) {
279         case 0: /* Implementation is still a stub, or the code wasn't set */
280                 is_valid = response->message == NULL;
281                 break;
282         case 500: /* Internal Server Error */
283         case 501: /* Not Implemented */
284         case 400: /* Missing parameter. */
285         case 404: /* Application does not exist. */
286         case 422: /* Event source does not exist. */
287                 is_valid = 1;
288                 break;
289         default:
290                 if (200 <= code && code <= 299) {
291                         is_valid = ast_ari_validate_application(
292                                 response->message);
293                 } else {
294                         ast_log(LOG_ERROR, "Invalid error response %d for /applications/{applicationName}/subscription\n", code);
295                         is_valid = 0;
296                 }
297         }
298
299         if (!is_valid) {
300                 ast_log(LOG_ERROR, "Response validation failed for /applications/{applicationName}/subscription\n");
301                 ast_ari_response_error(response, 500,
302                         "Internal Server Error", "Response validation failed");
303         }
304 #endif /* AST_DEVMODE */
305
306 fin: __attribute__((unused))
307         ast_free(args.event_source_parse);
308         ast_free(args.event_source);
309         return;
310 }
311 int ast_ari_applications_unsubscribe_parse_body(
312         struct ast_json *body,
313         struct ast_ari_applications_unsubscribe_args *args)
314 {
315         struct ast_json *field;
316         /* Parse query parameters out of it */
317         field = ast_json_object_get(body, "eventSource");
318         if (field) {
319                 /* If they were silly enough to both pass in a query param and a
320                  * JSON body, free up the query value.
321                  */
322                 ast_free(args->event_source);
323                 if (ast_json_typeof(field) == AST_JSON_ARRAY) {
324                         /* Multiple param passed as array */
325                         size_t i;
326                         args->event_source_count = ast_json_array_size(field);
327                         args->event_source = ast_malloc(sizeof(*args->event_source) * args->event_source_count);
328
329                         if (!args->event_source) {
330                                 return -1;
331                         }
332
333                         for (i = 0; i < args->event_source_count; ++i) {
334                                 args->event_source[i] = ast_json_string_get(ast_json_array_get(field, i));
335                         }
336                 } else {
337                         /* Multiple param passed as single value */
338                         args->event_source_count = 1;
339                         args->event_source = ast_malloc(sizeof(*args->event_source) * args->event_source_count);
340                         if (!args->event_source) {
341                                 return -1;
342                         }
343                         args->event_source[0] = ast_json_string_get(field);
344                 }
345         }
346         return 0;
347 }
348
349 /*!
350  * \brief Parameter parsing callback for /applications/{applicationName}/subscription.
351  * \param get_params GET parameters in the HTTP request.
352  * \param path_vars Path variables extracted from the request.
353  * \param headers HTTP headers.
354  * \param[out] response Response to the HTTP request.
355  */
356 static void ast_ari_applications_unsubscribe_cb(
357         struct ast_tcptls_session_instance *ser,
358         struct ast_variable *get_params, struct ast_variable *path_vars,
359         struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
360 {
361         struct ast_ari_applications_unsubscribe_args args = {};
362         struct ast_variable *i;
363 #if defined(AST_DEVMODE)
364         int is_valid;
365         int code;
366 #endif /* AST_DEVMODE */
367
368         for (i = get_params; i; i = i->next) {
369                 if (strcmp(i->name, "eventSource") == 0) {
370                         /* Parse comma separated list */
371                         char *vals[MAX_VALS];
372                         size_t j;
373
374                         args.event_source_parse = ast_strdup(i->value);
375                         if (!args.event_source_parse) {
376                                 ast_ari_response_alloc_failed(response);
377                                 goto fin;
378                         }
379
380                         if (strlen(args.event_source_parse) == 0) {
381                                 /* ast_app_separate_args can't handle "" */
382                                 args.event_source_count = 1;
383                                 vals[0] = args.event_source_parse;
384                         } else {
385                                 args.event_source_count = ast_app_separate_args(
386                                         args.event_source_parse, ',', vals,
387                                         ARRAY_LEN(vals));
388                         }
389
390                         if (args.event_source_count == 0) {
391                                 ast_ari_response_alloc_failed(response);
392                                 goto fin;
393                         }
394
395                         if (args.event_source_count >= MAX_VALS) {
396                                 ast_ari_response_error(response, 400,
397                                         "Bad Request",
398                                         "Too many values for event_source");
399                                 goto fin;
400                         }
401
402                         args.event_source = ast_malloc(sizeof(*args.event_source) * args.event_source_count);
403                         if (!args.event_source) {
404                                 ast_ari_response_alloc_failed(response);
405                                 goto fin;
406                         }
407
408                         for (j = 0; j < args.event_source_count; ++j) {
409                                 args.event_source[j] = (vals[j]);
410                         }
411                 } else
412                 {}
413         }
414         for (i = path_vars; i; i = i->next) {
415                 if (strcmp(i->name, "applicationName") == 0) {
416                         args.application_name = (i->value);
417                 } else
418                 {}
419         }
420         if (ast_ari_applications_unsubscribe_parse_body(body, &args)) {
421                 ast_ari_response_alloc_failed(response);
422                 goto fin;
423         }
424         ast_ari_applications_unsubscribe(headers, &args, response);
425 #if defined(AST_DEVMODE)
426         code = response->response_code;
427
428         switch (code) {
429         case 0: /* Implementation is still a stub, or the code wasn't set */
430                 is_valid = response->message == NULL;
431                 break;
432         case 500: /* Internal Server Error */
433         case 501: /* Not Implemented */
434         case 400: /* Missing parameter; event source scheme not recognized. */
435         case 404: /* Application does not exist. */
436         case 409: /* Application not subscribed to event source. */
437         case 422: /* Event source does not exist. */
438                 is_valid = 1;
439                 break;
440         default:
441                 if (200 <= code && code <= 299) {
442                         is_valid = ast_ari_validate_application(
443                                 response->message);
444                 } else {
445                         ast_log(LOG_ERROR, "Invalid error response %d for /applications/{applicationName}/subscription\n", code);
446                         is_valid = 0;
447                 }
448         }
449
450         if (!is_valid) {
451                 ast_log(LOG_ERROR, "Response validation failed for /applications/{applicationName}/subscription\n");
452                 ast_ari_response_error(response, 500,
453                         "Internal Server Error", "Response validation failed");
454         }
455 #endif /* AST_DEVMODE */
456
457 fin: __attribute__((unused))
458         ast_free(args.event_source_parse);
459         ast_free(args.event_source);
460         return;
461 }
462
463 /*! \brief REST handler for /api-docs/applications.json */
464 static struct stasis_rest_handlers applications_applicationName_subscription = {
465         .path_segment = "subscription",
466         .callbacks = {
467                 [AST_HTTP_POST] = ast_ari_applications_subscribe_cb,
468                 [AST_HTTP_DELETE] = ast_ari_applications_unsubscribe_cb,
469         },
470         .num_children = 0,
471         .children = {  }
472 };
473 /*! \brief REST handler for /api-docs/applications.json */
474 static struct stasis_rest_handlers applications_applicationName = {
475         .path_segment = "applicationName",
476         .is_wildcard = 1,
477         .callbacks = {
478                 [AST_HTTP_GET] = ast_ari_applications_get_cb,
479         },
480         .num_children = 1,
481         .children = { &applications_applicationName_subscription, }
482 };
483 /*! \brief REST handler for /api-docs/applications.json */
484 static struct stasis_rest_handlers applications = {
485         .path_segment = "applications",
486         .callbacks = {
487                 [AST_HTTP_GET] = ast_ari_applications_list_cb,
488         },
489         .num_children = 1,
490         .children = { &applications_applicationName, }
491 };
492
493 static int unload_module(void)
494 {
495         ast_ari_remove_handler(&applications);
496         stasis_app_unref();
497         return 0;
498 }
499
500 static int load_module(void)
501 {
502         int res = 0;
503         stasis_app_ref();
504         res |= ast_ari_add_handler(&applications);
505         if (res) {
506                 unload_module();
507                 return AST_MODULE_LOAD_DECLINE;
508         }
509
510         return AST_MODULE_LOAD_SUCCESS;
511 }
512
513 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Stasis application resources",
514         .support_level = AST_MODULE_SUPPORT_CORE,
515         .load = load_module,
516         .unload = unload_module,
517         .nonoptreq = "res_ari,res_stasis",
518 );