ARI: Support channel variables in originate
[asterisk/asterisk.git] / res / res_ari_bridges.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 /*
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 Bridge 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_stasis</depend>
37         <support_level>core</support_level>
38  ***/
39
40 #include "asterisk.h"
41
42 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
43
44 #include "asterisk/app.h"
45 #include "asterisk/module.h"
46 #include "asterisk/stasis_app.h"
47 #include "ari/resource_bridges.h"
48 #if defined(AST_DEVMODE)
49 #include "ari/ari_model_validators.h"
50 #endif
51
52 #define MAX_VALS 128
53
54 /*!
55  * \brief Parameter parsing callback for /bridges.
56  * \param get_params GET parameters in the HTTP request.
57  * \param path_vars Path variables extracted from the request.
58  * \param headers HTTP headers.
59  * \param[out] response Response to the HTTP request.
60  */
61 static void ast_ari_bridges_list_cb(
62         struct ast_tcptls_session_instance *ser,
63         struct ast_variable *get_params, struct ast_variable *path_vars,
64         struct ast_variable *headers, struct ast_ari_response *response)
65 {
66         struct ast_ari_bridges_list_args args = {};
67         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
68 #if defined(AST_DEVMODE)
69         int is_valid;
70         int code;
71 #endif /* AST_DEVMODE */
72
73         ast_ari_bridges_list(headers, &args, response);
74 #if defined(AST_DEVMODE)
75         code = response->response_code;
76
77         switch (code) {
78         case 0: /* Implementation is still a stub, or the code wasn't set */
79                 is_valid = response->message == NULL;
80                 break;
81         case 500: /* Internal Server Error */
82         case 501: /* Not Implemented */
83                 is_valid = 1;
84                 break;
85         default:
86                 if (200 <= code && code <= 299) {
87                         is_valid = ast_ari_validate_list(response->message,
88                                 ast_ari_validate_bridge_fn());
89                 } else {
90                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges\n", code);
91                         is_valid = 0;
92                 }
93         }
94
95         if (!is_valid) {
96                 ast_log(LOG_ERROR, "Response validation failed for /bridges\n");
97                 ast_ari_response_error(response, 500,
98                         "Internal Server Error", "Response validation failed");
99         }
100 #endif /* AST_DEVMODE */
101
102 fin: __attribute__((unused))
103         return;
104 }
105 int ast_ari_bridges_create_parse_body(
106         struct ast_json *body,
107         struct ast_ari_bridges_create_args *args)
108 {
109         struct ast_json *field;
110         /* Parse query parameters out of it */
111         field = ast_json_object_get(body, "type");
112         if (field) {
113                 args->type = ast_json_string_get(field);
114         }
115         field = ast_json_object_get(body, "name");
116         if (field) {
117                 args->name = ast_json_string_get(field);
118         }
119         return 0;
120 }
121
122 /*!
123  * \brief Parameter parsing callback for /bridges.
124  * \param get_params GET parameters in the HTTP request.
125  * \param path_vars Path variables extracted from the request.
126  * \param headers HTTP headers.
127  * \param[out] response Response to the HTTP request.
128  */
129 static void ast_ari_bridges_create_cb(
130         struct ast_tcptls_session_instance *ser,
131         struct ast_variable *get_params, struct ast_variable *path_vars,
132         struct ast_variable *headers, struct ast_ari_response *response)
133 {
134         struct ast_ari_bridges_create_args args = {};
135         struct ast_variable *i;
136         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
137 #if defined(AST_DEVMODE)
138         int is_valid;
139         int code;
140 #endif /* AST_DEVMODE */
141
142         for (i = get_params; i; i = i->next) {
143                 if (strcmp(i->name, "type") == 0) {
144                         args.type = (i->value);
145                 } else
146                 if (strcmp(i->name, "name") == 0) {
147                         args.name = (i->value);
148                 } else
149                 {}
150         }
151         /* Look for a JSON request entity */
152         body = ast_http_get_json(ser, headers);
153         if (!body) {
154                 switch (errno) {
155                 case EFBIG:
156                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
157                         goto fin;
158                 case ENOMEM:
159                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
160                         goto fin;
161                 case EIO:
162                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
163                         goto fin;
164                 }
165         }
166         if (ast_ari_bridges_create_parse_body(body, &args)) {
167                 ast_ari_response_alloc_failed(response);
168                 goto fin;
169         }
170         ast_ari_bridges_create(headers, &args, response);
171 #if defined(AST_DEVMODE)
172         code = response->response_code;
173
174         switch (code) {
175         case 0: /* Implementation is still a stub, or the code wasn't set */
176                 is_valid = response->message == NULL;
177                 break;
178         case 500: /* Internal Server Error */
179         case 501: /* Not Implemented */
180                 is_valid = 1;
181                 break;
182         default:
183                 if (200 <= code && code <= 299) {
184                         is_valid = ast_ari_validate_bridge(
185                                 response->message);
186                 } else {
187                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges\n", code);
188                         is_valid = 0;
189                 }
190         }
191
192         if (!is_valid) {
193                 ast_log(LOG_ERROR, "Response validation failed for /bridges\n");
194                 ast_ari_response_error(response, 500,
195                         "Internal Server Error", "Response validation failed");
196         }
197 #endif /* AST_DEVMODE */
198
199 fin: __attribute__((unused))
200         return;
201 }
202 /*!
203  * \brief Parameter parsing callback for /bridges/{bridgeId}.
204  * \param get_params GET parameters in the HTTP request.
205  * \param path_vars Path variables extracted from the request.
206  * \param headers HTTP headers.
207  * \param[out] response Response to the HTTP request.
208  */
209 static void ast_ari_bridges_get_cb(
210         struct ast_tcptls_session_instance *ser,
211         struct ast_variable *get_params, struct ast_variable *path_vars,
212         struct ast_variable *headers, struct ast_ari_response *response)
213 {
214         struct ast_ari_bridges_get_args args = {};
215         struct ast_variable *i;
216         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
217 #if defined(AST_DEVMODE)
218         int is_valid;
219         int code;
220 #endif /* AST_DEVMODE */
221
222         for (i = path_vars; i; i = i->next) {
223                 if (strcmp(i->name, "bridgeId") == 0) {
224                         args.bridge_id = (i->value);
225                 } else
226                 {}
227         }
228         ast_ari_bridges_get(headers, &args, response);
229 #if defined(AST_DEVMODE)
230         code = response->response_code;
231
232         switch (code) {
233         case 0: /* Implementation is still a stub, or the code wasn't set */
234                 is_valid = response->message == NULL;
235                 break;
236         case 500: /* Internal Server Error */
237         case 501: /* Not Implemented */
238         case 404: /* Bridge not found */
239                 is_valid = 1;
240                 break;
241         default:
242                 if (200 <= code && code <= 299) {
243                         is_valid = ast_ari_validate_bridge(
244                                 response->message);
245                 } else {
246                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}\n", code);
247                         is_valid = 0;
248                 }
249         }
250
251         if (!is_valid) {
252                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}\n");
253                 ast_ari_response_error(response, 500,
254                         "Internal Server Error", "Response validation failed");
255         }
256 #endif /* AST_DEVMODE */
257
258 fin: __attribute__((unused))
259         return;
260 }
261 /*!
262  * \brief Parameter parsing callback for /bridges/{bridgeId}.
263  * \param get_params GET parameters in the HTTP request.
264  * \param path_vars Path variables extracted from the request.
265  * \param headers HTTP headers.
266  * \param[out] response Response to the HTTP request.
267  */
268 static void ast_ari_bridges_destroy_cb(
269         struct ast_tcptls_session_instance *ser,
270         struct ast_variable *get_params, struct ast_variable *path_vars,
271         struct ast_variable *headers, struct ast_ari_response *response)
272 {
273         struct ast_ari_bridges_destroy_args args = {};
274         struct ast_variable *i;
275         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
276 #if defined(AST_DEVMODE)
277         int is_valid;
278         int code;
279 #endif /* AST_DEVMODE */
280
281         for (i = path_vars; i; i = i->next) {
282                 if (strcmp(i->name, "bridgeId") == 0) {
283                         args.bridge_id = (i->value);
284                 } else
285                 {}
286         }
287         ast_ari_bridges_destroy(headers, &args, response);
288 #if defined(AST_DEVMODE)
289         code = response->response_code;
290
291         switch (code) {
292         case 0: /* Implementation is still a stub, or the code wasn't set */
293                 is_valid = response->message == NULL;
294                 break;
295         case 500: /* Internal Server Error */
296         case 501: /* Not Implemented */
297         case 404: /* Bridge not found */
298                 is_valid = 1;
299                 break;
300         default:
301                 if (200 <= code && code <= 299) {
302                         is_valid = ast_ari_validate_void(
303                                 response->message);
304                 } else {
305                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}\n", code);
306                         is_valid = 0;
307                 }
308         }
309
310         if (!is_valid) {
311                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}\n");
312                 ast_ari_response_error(response, 500,
313                         "Internal Server Error", "Response validation failed");
314         }
315 #endif /* AST_DEVMODE */
316
317 fin: __attribute__((unused))
318         return;
319 }
320 int ast_ari_bridges_add_channel_parse_body(
321         struct ast_json *body,
322         struct ast_ari_bridges_add_channel_args *args)
323 {
324         struct ast_json *field;
325         /* Parse query parameters out of it */
326         field = ast_json_object_get(body, "channel");
327         if (field) {
328                 /* If they were silly enough to both pass in a query param and a
329                  * JSON body, free up the query value.
330                  */
331                 ast_free(args->channel);
332                 if (ast_json_typeof(field) == AST_JSON_ARRAY) {
333                         /* Multiple param passed as array */
334                         size_t i;
335                         args->channel_count = ast_json_array_size(field);
336                         args->channel = ast_malloc(sizeof(*args->channel) * args->channel_count);
337
338                         if (!args->channel) {
339                                 return -1;
340                         }
341
342                         for (i = 0; i < args->channel_count; ++i) {
343                                 args->channel[i] = ast_json_string_get(ast_json_array_get(field, i));
344                         }
345                 } else {
346                         /* Multiple param passed as single value */
347                         args->channel_count = 1;
348                         args->channel = ast_malloc(sizeof(*args->channel) * args->channel_count);
349                         if (!args->channel) {
350                                 return -1;
351                         }
352                         args->channel[0] = ast_json_string_get(field);
353                 }
354         }
355         field = ast_json_object_get(body, "role");
356         if (field) {
357                 args->role = ast_json_string_get(field);
358         }
359         return 0;
360 }
361
362 /*!
363  * \brief Parameter parsing callback for /bridges/{bridgeId}/addChannel.
364  * \param get_params GET parameters in the HTTP request.
365  * \param path_vars Path variables extracted from the request.
366  * \param headers HTTP headers.
367  * \param[out] response Response to the HTTP request.
368  */
369 static void ast_ari_bridges_add_channel_cb(
370         struct ast_tcptls_session_instance *ser,
371         struct ast_variable *get_params, struct ast_variable *path_vars,
372         struct ast_variable *headers, struct ast_ari_response *response)
373 {
374         struct ast_ari_bridges_add_channel_args args = {};
375         struct ast_variable *i;
376         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
377 #if defined(AST_DEVMODE)
378         int is_valid;
379         int code;
380 #endif /* AST_DEVMODE */
381
382         for (i = get_params; i; i = i->next) {
383                 if (strcmp(i->name, "channel") == 0) {
384                         /* Parse comma separated list */
385                         char *vals[MAX_VALS];
386                         size_t j;
387
388                         args.channel_parse = ast_strdup(i->value);
389                         if (!args.channel_parse) {
390                                 ast_ari_response_alloc_failed(response);
391                                 goto fin;
392                         }
393
394                         if (strlen(args.channel_parse) == 0) {
395                                 /* ast_app_separate_args can't handle "" */
396                                 args.channel_count = 1;
397                                 vals[0] = args.channel_parse;
398                         } else {
399                                 args.channel_count = ast_app_separate_args(
400                                         args.channel_parse, ',', vals,
401                                         ARRAY_LEN(vals));
402                         }
403
404                         if (args.channel_count == 0) {
405                                 ast_ari_response_alloc_failed(response);
406                                 goto fin;
407                         }
408
409                         if (args.channel_count >= MAX_VALS) {
410                                 ast_ari_response_error(response, 400,
411                                         "Bad Request",
412                                         "Too many values for channel");
413                                 goto fin;
414                         }
415
416                         args.channel = ast_malloc(sizeof(*args.channel) * args.channel_count);
417                         if (!args.channel) {
418                                 ast_ari_response_alloc_failed(response);
419                                 goto fin;
420                         }
421
422                         for (j = 0; j < args.channel_count; ++j) {
423                                 args.channel[j] = (vals[j]);
424                         }
425                 } else
426                 if (strcmp(i->name, "role") == 0) {
427                         args.role = (i->value);
428                 } else
429                 {}
430         }
431         for (i = path_vars; i; i = i->next) {
432                 if (strcmp(i->name, "bridgeId") == 0) {
433                         args.bridge_id = (i->value);
434                 } else
435                 {}
436         }
437         /* Look for a JSON request entity */
438         body = ast_http_get_json(ser, headers);
439         if (!body) {
440                 switch (errno) {
441                 case EFBIG:
442                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
443                         goto fin;
444                 case ENOMEM:
445                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
446                         goto fin;
447                 case EIO:
448                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
449                         goto fin;
450                 }
451         }
452         if (ast_ari_bridges_add_channel_parse_body(body, &args)) {
453                 ast_ari_response_alloc_failed(response);
454                 goto fin;
455         }
456         ast_ari_bridges_add_channel(headers, &args, response);
457 #if defined(AST_DEVMODE)
458         code = response->response_code;
459
460         switch (code) {
461         case 0: /* Implementation is still a stub, or the code wasn't set */
462                 is_valid = response->message == NULL;
463                 break;
464         case 500: /* Internal Server Error */
465         case 501: /* Not Implemented */
466         case 400: /* Channel not found */
467         case 404: /* Bridge not found */
468         case 409: /* Bridge not in Stasis application; Channel currently recording */
469         case 422: /* Channel not in Stasis application */
470                 is_valid = 1;
471                 break;
472         default:
473                 if (200 <= code && code <= 299) {
474                         is_valid = ast_ari_validate_void(
475                                 response->message);
476                 } else {
477                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/addChannel\n", code);
478                         is_valid = 0;
479                 }
480         }
481
482         if (!is_valid) {
483                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/addChannel\n");
484                 ast_ari_response_error(response, 500,
485                         "Internal Server Error", "Response validation failed");
486         }
487 #endif /* AST_DEVMODE */
488
489 fin: __attribute__((unused))
490         ast_free(args.channel_parse);
491         ast_free(args.channel);
492         return;
493 }
494 int ast_ari_bridges_remove_channel_parse_body(
495         struct ast_json *body,
496         struct ast_ari_bridges_remove_channel_args *args)
497 {
498         struct ast_json *field;
499         /* Parse query parameters out of it */
500         field = ast_json_object_get(body, "channel");
501         if (field) {
502                 /* If they were silly enough to both pass in a query param and a
503                  * JSON body, free up the query value.
504                  */
505                 ast_free(args->channel);
506                 if (ast_json_typeof(field) == AST_JSON_ARRAY) {
507                         /* Multiple param passed as array */
508                         size_t i;
509                         args->channel_count = ast_json_array_size(field);
510                         args->channel = ast_malloc(sizeof(*args->channel) * args->channel_count);
511
512                         if (!args->channel) {
513                                 return -1;
514                         }
515
516                         for (i = 0; i < args->channel_count; ++i) {
517                                 args->channel[i] = ast_json_string_get(ast_json_array_get(field, i));
518                         }
519                 } else {
520                         /* Multiple param passed as single value */
521                         args->channel_count = 1;
522                         args->channel = ast_malloc(sizeof(*args->channel) * args->channel_count);
523                         if (!args->channel) {
524                                 return -1;
525                         }
526                         args->channel[0] = ast_json_string_get(field);
527                 }
528         }
529         return 0;
530 }
531
532 /*!
533  * \brief Parameter parsing callback for /bridges/{bridgeId}/removeChannel.
534  * \param get_params GET parameters in the HTTP request.
535  * \param path_vars Path variables extracted from the request.
536  * \param headers HTTP headers.
537  * \param[out] response Response to the HTTP request.
538  */
539 static void ast_ari_bridges_remove_channel_cb(
540         struct ast_tcptls_session_instance *ser,
541         struct ast_variable *get_params, struct ast_variable *path_vars,
542         struct ast_variable *headers, struct ast_ari_response *response)
543 {
544         struct ast_ari_bridges_remove_channel_args args = {};
545         struct ast_variable *i;
546         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
547 #if defined(AST_DEVMODE)
548         int is_valid;
549         int code;
550 #endif /* AST_DEVMODE */
551
552         for (i = get_params; i; i = i->next) {
553                 if (strcmp(i->name, "channel") == 0) {
554                         /* Parse comma separated list */
555                         char *vals[MAX_VALS];
556                         size_t j;
557
558                         args.channel_parse = ast_strdup(i->value);
559                         if (!args.channel_parse) {
560                                 ast_ari_response_alloc_failed(response);
561                                 goto fin;
562                         }
563
564                         if (strlen(args.channel_parse) == 0) {
565                                 /* ast_app_separate_args can't handle "" */
566                                 args.channel_count = 1;
567                                 vals[0] = args.channel_parse;
568                         } else {
569                                 args.channel_count = ast_app_separate_args(
570                                         args.channel_parse, ',', vals,
571                                         ARRAY_LEN(vals));
572                         }
573
574                         if (args.channel_count == 0) {
575                                 ast_ari_response_alloc_failed(response);
576                                 goto fin;
577                         }
578
579                         if (args.channel_count >= MAX_VALS) {
580                                 ast_ari_response_error(response, 400,
581                                         "Bad Request",
582                                         "Too many values for channel");
583                                 goto fin;
584                         }
585
586                         args.channel = ast_malloc(sizeof(*args.channel) * args.channel_count);
587                         if (!args.channel) {
588                                 ast_ari_response_alloc_failed(response);
589                                 goto fin;
590                         }
591
592                         for (j = 0; j < args.channel_count; ++j) {
593                                 args.channel[j] = (vals[j]);
594                         }
595                 } else
596                 {}
597         }
598         for (i = path_vars; i; i = i->next) {
599                 if (strcmp(i->name, "bridgeId") == 0) {
600                         args.bridge_id = (i->value);
601                 } else
602                 {}
603         }
604         /* Look for a JSON request entity */
605         body = ast_http_get_json(ser, headers);
606         if (!body) {
607                 switch (errno) {
608                 case EFBIG:
609                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
610                         goto fin;
611                 case ENOMEM:
612                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
613                         goto fin;
614                 case EIO:
615                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
616                         goto fin;
617                 }
618         }
619         if (ast_ari_bridges_remove_channel_parse_body(body, &args)) {
620                 ast_ari_response_alloc_failed(response);
621                 goto fin;
622         }
623         ast_ari_bridges_remove_channel(headers, &args, response);
624 #if defined(AST_DEVMODE)
625         code = response->response_code;
626
627         switch (code) {
628         case 0: /* Implementation is still a stub, or the code wasn't set */
629                 is_valid = response->message == NULL;
630                 break;
631         case 500: /* Internal Server Error */
632         case 501: /* Not Implemented */
633         case 400: /* Channel not found */
634         case 404: /* Bridge not found */
635         case 409: /* Bridge not in Stasis application */
636         case 422: /* Channel not in this bridge */
637                 is_valid = 1;
638                 break;
639         default:
640                 if (200 <= code && code <= 299) {
641                         is_valid = ast_ari_validate_void(
642                                 response->message);
643                 } else {
644                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/removeChannel\n", code);
645                         is_valid = 0;
646                 }
647         }
648
649         if (!is_valid) {
650                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/removeChannel\n");
651                 ast_ari_response_error(response, 500,
652                         "Internal Server Error", "Response validation failed");
653         }
654 #endif /* AST_DEVMODE */
655
656 fin: __attribute__((unused))
657         ast_free(args.channel_parse);
658         ast_free(args.channel);
659         return;
660 }
661 int ast_ari_bridges_start_moh_parse_body(
662         struct ast_json *body,
663         struct ast_ari_bridges_start_moh_args *args)
664 {
665         struct ast_json *field;
666         /* Parse query parameters out of it */
667         field = ast_json_object_get(body, "mohClass");
668         if (field) {
669                 args->moh_class = ast_json_string_get(field);
670         }
671         return 0;
672 }
673
674 /*!
675  * \brief Parameter parsing callback for /bridges/{bridgeId}/moh.
676  * \param get_params GET parameters in the HTTP request.
677  * \param path_vars Path variables extracted from the request.
678  * \param headers HTTP headers.
679  * \param[out] response Response to the HTTP request.
680  */
681 static void ast_ari_bridges_start_moh_cb(
682         struct ast_tcptls_session_instance *ser,
683         struct ast_variable *get_params, struct ast_variable *path_vars,
684         struct ast_variable *headers, struct ast_ari_response *response)
685 {
686         struct ast_ari_bridges_start_moh_args args = {};
687         struct ast_variable *i;
688         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
689 #if defined(AST_DEVMODE)
690         int is_valid;
691         int code;
692 #endif /* AST_DEVMODE */
693
694         for (i = get_params; i; i = i->next) {
695                 if (strcmp(i->name, "mohClass") == 0) {
696                         args.moh_class = (i->value);
697                 } else
698                 {}
699         }
700         for (i = path_vars; i; i = i->next) {
701                 if (strcmp(i->name, "bridgeId") == 0) {
702                         args.bridge_id = (i->value);
703                 } else
704                 {}
705         }
706         /* Look for a JSON request entity */
707         body = ast_http_get_json(ser, headers);
708         if (!body) {
709                 switch (errno) {
710                 case EFBIG:
711                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
712                         goto fin;
713                 case ENOMEM:
714                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
715                         goto fin;
716                 case EIO:
717                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
718                         goto fin;
719                 }
720         }
721         if (ast_ari_bridges_start_moh_parse_body(body, &args)) {
722                 ast_ari_response_alloc_failed(response);
723                 goto fin;
724         }
725         ast_ari_bridges_start_moh(headers, &args, response);
726 #if defined(AST_DEVMODE)
727         code = response->response_code;
728
729         switch (code) {
730         case 0: /* Implementation is still a stub, or the code wasn't set */
731                 is_valid = response->message == NULL;
732                 break;
733         case 500: /* Internal Server Error */
734         case 501: /* Not Implemented */
735         case 404: /* Bridge not found */
736         case 409: /* Bridge not in Stasis application */
737                 is_valid = 1;
738                 break;
739         default:
740                 if (200 <= code && code <= 299) {
741                         is_valid = ast_ari_validate_void(
742                                 response->message);
743                 } else {
744                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/moh\n", code);
745                         is_valid = 0;
746                 }
747         }
748
749         if (!is_valid) {
750                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/moh\n");
751                 ast_ari_response_error(response, 500,
752                         "Internal Server Error", "Response validation failed");
753         }
754 #endif /* AST_DEVMODE */
755
756 fin: __attribute__((unused))
757         return;
758 }
759 /*!
760  * \brief Parameter parsing callback for /bridges/{bridgeId}/moh.
761  * \param get_params GET parameters in the HTTP request.
762  * \param path_vars Path variables extracted from the request.
763  * \param headers HTTP headers.
764  * \param[out] response Response to the HTTP request.
765  */
766 static void ast_ari_bridges_stop_moh_cb(
767         struct ast_tcptls_session_instance *ser,
768         struct ast_variable *get_params, struct ast_variable *path_vars,
769         struct ast_variable *headers, struct ast_ari_response *response)
770 {
771         struct ast_ari_bridges_stop_moh_args args = {};
772         struct ast_variable *i;
773         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
774 #if defined(AST_DEVMODE)
775         int is_valid;
776         int code;
777 #endif /* AST_DEVMODE */
778
779         for (i = path_vars; i; i = i->next) {
780                 if (strcmp(i->name, "bridgeId") == 0) {
781                         args.bridge_id = (i->value);
782                 } else
783                 {}
784         }
785         ast_ari_bridges_stop_moh(headers, &args, response);
786 #if defined(AST_DEVMODE)
787         code = response->response_code;
788
789         switch (code) {
790         case 0: /* Implementation is still a stub, or the code wasn't set */
791                 is_valid = response->message == NULL;
792                 break;
793         case 500: /* Internal Server Error */
794         case 501: /* Not Implemented */
795         case 404: /* Bridge not found */
796         case 409: /* Bridge not in Stasis application */
797                 is_valid = 1;
798                 break;
799         default:
800                 if (200 <= code && code <= 299) {
801                         is_valid = ast_ari_validate_void(
802                                 response->message);
803                 } else {
804                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/moh\n", code);
805                         is_valid = 0;
806                 }
807         }
808
809         if (!is_valid) {
810                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/moh\n");
811                 ast_ari_response_error(response, 500,
812                         "Internal Server Error", "Response validation failed");
813         }
814 #endif /* AST_DEVMODE */
815
816 fin: __attribute__((unused))
817         return;
818 }
819 int ast_ari_bridges_play_parse_body(
820         struct ast_json *body,
821         struct ast_ari_bridges_play_args *args)
822 {
823         struct ast_json *field;
824         /* Parse query parameters out of it */
825         field = ast_json_object_get(body, "media");
826         if (field) {
827                 args->media = ast_json_string_get(field);
828         }
829         field = ast_json_object_get(body, "lang");
830         if (field) {
831                 args->lang = ast_json_string_get(field);
832         }
833         field = ast_json_object_get(body, "offsetms");
834         if (field) {
835                 args->offsetms = ast_json_integer_get(field);
836         }
837         field = ast_json_object_get(body, "skipms");
838         if (field) {
839                 args->skipms = ast_json_integer_get(field);
840         }
841         return 0;
842 }
843
844 /*!
845  * \brief Parameter parsing callback for /bridges/{bridgeId}/play.
846  * \param get_params GET parameters in the HTTP request.
847  * \param path_vars Path variables extracted from the request.
848  * \param headers HTTP headers.
849  * \param[out] response Response to the HTTP request.
850  */
851 static void ast_ari_bridges_play_cb(
852         struct ast_tcptls_session_instance *ser,
853         struct ast_variable *get_params, struct ast_variable *path_vars,
854         struct ast_variable *headers, struct ast_ari_response *response)
855 {
856         struct ast_ari_bridges_play_args args = {};
857         struct ast_variable *i;
858         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
859 #if defined(AST_DEVMODE)
860         int is_valid;
861         int code;
862 #endif /* AST_DEVMODE */
863
864         for (i = get_params; i; i = i->next) {
865                 if (strcmp(i->name, "media") == 0) {
866                         args.media = (i->value);
867                 } else
868                 if (strcmp(i->name, "lang") == 0) {
869                         args.lang = (i->value);
870                 } else
871                 if (strcmp(i->name, "offsetms") == 0) {
872                         args.offsetms = atoi(i->value);
873                 } else
874                 if (strcmp(i->name, "skipms") == 0) {
875                         args.skipms = atoi(i->value);
876                 } else
877                 {}
878         }
879         for (i = path_vars; i; i = i->next) {
880                 if (strcmp(i->name, "bridgeId") == 0) {
881                         args.bridge_id = (i->value);
882                 } else
883                 {}
884         }
885         /* Look for a JSON request entity */
886         body = ast_http_get_json(ser, headers);
887         if (!body) {
888                 switch (errno) {
889                 case EFBIG:
890                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
891                         goto fin;
892                 case ENOMEM:
893                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
894                         goto fin;
895                 case EIO:
896                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
897                         goto fin;
898                 }
899         }
900         if (ast_ari_bridges_play_parse_body(body, &args)) {
901                 ast_ari_response_alloc_failed(response);
902                 goto fin;
903         }
904         ast_ari_bridges_play(headers, &args, response);
905 #if defined(AST_DEVMODE)
906         code = response->response_code;
907
908         switch (code) {
909         case 0: /* Implementation is still a stub, or the code wasn't set */
910                 is_valid = response->message == NULL;
911                 break;
912         case 500: /* Internal Server Error */
913         case 501: /* Not Implemented */
914         case 404: /* Bridge not found */
915         case 409: /* Bridge not in a Stasis application */
916                 is_valid = 1;
917                 break;
918         default:
919                 if (200 <= code && code <= 299) {
920                         is_valid = ast_ari_validate_playback(
921                                 response->message);
922                 } else {
923                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/play\n", code);
924                         is_valid = 0;
925                 }
926         }
927
928         if (!is_valid) {
929                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/play\n");
930                 ast_ari_response_error(response, 500,
931                         "Internal Server Error", "Response validation failed");
932         }
933 #endif /* AST_DEVMODE */
934
935 fin: __attribute__((unused))
936         return;
937 }
938 int ast_ari_bridges_record_parse_body(
939         struct ast_json *body,
940         struct ast_ari_bridges_record_args *args)
941 {
942         struct ast_json *field;
943         /* Parse query parameters out of it */
944         field = ast_json_object_get(body, "name");
945         if (field) {
946                 args->name = ast_json_string_get(field);
947         }
948         field = ast_json_object_get(body, "format");
949         if (field) {
950                 args->format = ast_json_string_get(field);
951         }
952         field = ast_json_object_get(body, "maxDurationSeconds");
953         if (field) {
954                 args->max_duration_seconds = ast_json_integer_get(field);
955         }
956         field = ast_json_object_get(body, "maxSilenceSeconds");
957         if (field) {
958                 args->max_silence_seconds = ast_json_integer_get(field);
959         }
960         field = ast_json_object_get(body, "ifExists");
961         if (field) {
962                 args->if_exists = ast_json_string_get(field);
963         }
964         field = ast_json_object_get(body, "beep");
965         if (field) {
966                 args->beep = ast_json_is_true(field);
967         }
968         field = ast_json_object_get(body, "terminateOn");
969         if (field) {
970                 args->terminate_on = ast_json_string_get(field);
971         }
972         return 0;
973 }
974
975 /*!
976  * \brief Parameter parsing callback for /bridges/{bridgeId}/record.
977  * \param get_params GET parameters in the HTTP request.
978  * \param path_vars Path variables extracted from the request.
979  * \param headers HTTP headers.
980  * \param[out] response Response to the HTTP request.
981  */
982 static void ast_ari_bridges_record_cb(
983         struct ast_tcptls_session_instance *ser,
984         struct ast_variable *get_params, struct ast_variable *path_vars,
985         struct ast_variable *headers, struct ast_ari_response *response)
986 {
987         struct ast_ari_bridges_record_args args = {};
988         struct ast_variable *i;
989         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
990 #if defined(AST_DEVMODE)
991         int is_valid;
992         int code;
993 #endif /* AST_DEVMODE */
994
995         for (i = get_params; i; i = i->next) {
996                 if (strcmp(i->name, "name") == 0) {
997                         args.name = (i->value);
998                 } else
999                 if (strcmp(i->name, "format") == 0) {
1000                         args.format = (i->value);
1001                 } else
1002                 if (strcmp(i->name, "maxDurationSeconds") == 0) {
1003                         args.max_duration_seconds = atoi(i->value);
1004                 } else
1005                 if (strcmp(i->name, "maxSilenceSeconds") == 0) {
1006                         args.max_silence_seconds = atoi(i->value);
1007                 } else
1008                 if (strcmp(i->name, "ifExists") == 0) {
1009                         args.if_exists = (i->value);
1010                 } else
1011                 if (strcmp(i->name, "beep") == 0) {
1012                         args.beep = ast_true(i->value);
1013                 } else
1014                 if (strcmp(i->name, "terminateOn") == 0) {
1015                         args.terminate_on = (i->value);
1016                 } else
1017                 {}
1018         }
1019         for (i = path_vars; i; i = i->next) {
1020                 if (strcmp(i->name, "bridgeId") == 0) {
1021                         args.bridge_id = (i->value);
1022                 } else
1023                 {}
1024         }
1025         /* Look for a JSON request entity */
1026         body = ast_http_get_json(ser, headers);
1027         if (!body) {
1028                 switch (errno) {
1029                 case EFBIG:
1030                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
1031                         goto fin;
1032                 case ENOMEM:
1033                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
1034                         goto fin;
1035                 case EIO:
1036                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
1037                         goto fin;
1038                 }
1039         }
1040         if (ast_ari_bridges_record_parse_body(body, &args)) {
1041                 ast_ari_response_alloc_failed(response);
1042                 goto fin;
1043         }
1044         ast_ari_bridges_record(headers, &args, response);
1045 #if defined(AST_DEVMODE)
1046         code = response->response_code;
1047
1048         switch (code) {
1049         case 0: /* Implementation is still a stub, or the code wasn't set */
1050                 is_valid = response->message == NULL;
1051                 break;
1052         case 500: /* Internal Server Error */
1053         case 501: /* Not Implemented */
1054         case 400: /* Invalid parameters */
1055         case 404: /* Bridge not found */
1056         case 409: /* Bridge is not in a Stasis application; A recording with the same name already exists on the system and can not be overwritten because it is in progress or ifExists=fail */
1057         case 422: /* The format specified is unknown on this system */
1058                 is_valid = 1;
1059                 break;
1060         default:
1061                 if (200 <= code && code <= 299) {
1062                         is_valid = ast_ari_validate_live_recording(
1063                                 response->message);
1064                 } else {
1065                         ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}/record\n", code);
1066                         is_valid = 0;
1067                 }
1068         }
1069
1070         if (!is_valid) {
1071                 ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}/record\n");
1072                 ast_ari_response_error(response, 500,
1073                         "Internal Server Error", "Response validation failed");
1074         }
1075 #endif /* AST_DEVMODE */
1076
1077 fin: __attribute__((unused))
1078         return;
1079 }
1080
1081 /*! \brief REST handler for /api-docs/bridges.{format} */
1082 static struct stasis_rest_handlers bridges_bridgeId_addChannel = {
1083         .path_segment = "addChannel",
1084         .callbacks = {
1085                 [AST_HTTP_POST] = ast_ari_bridges_add_channel_cb,
1086         },
1087         .num_children = 0,
1088         .children = {  }
1089 };
1090 /*! \brief REST handler for /api-docs/bridges.{format} */
1091 static struct stasis_rest_handlers bridges_bridgeId_removeChannel = {
1092         .path_segment = "removeChannel",
1093         .callbacks = {
1094                 [AST_HTTP_POST] = ast_ari_bridges_remove_channel_cb,
1095         },
1096         .num_children = 0,
1097         .children = {  }
1098 };
1099 /*! \brief REST handler for /api-docs/bridges.{format} */
1100 static struct stasis_rest_handlers bridges_bridgeId_moh = {
1101         .path_segment = "moh",
1102         .callbacks = {
1103                 [AST_HTTP_POST] = ast_ari_bridges_start_moh_cb,
1104                 [AST_HTTP_DELETE] = ast_ari_bridges_stop_moh_cb,
1105         },
1106         .num_children = 0,
1107         .children = {  }
1108 };
1109 /*! \brief REST handler for /api-docs/bridges.{format} */
1110 static struct stasis_rest_handlers bridges_bridgeId_play = {
1111         .path_segment = "play",
1112         .callbacks = {
1113                 [AST_HTTP_POST] = ast_ari_bridges_play_cb,
1114         },
1115         .num_children = 0,
1116         .children = {  }
1117 };
1118 /*! \brief REST handler for /api-docs/bridges.{format} */
1119 static struct stasis_rest_handlers bridges_bridgeId_record = {
1120         .path_segment = "record",
1121         .callbacks = {
1122                 [AST_HTTP_POST] = ast_ari_bridges_record_cb,
1123         },
1124         .num_children = 0,
1125         .children = {  }
1126 };
1127 /*! \brief REST handler for /api-docs/bridges.{format} */
1128 static struct stasis_rest_handlers bridges_bridgeId = {
1129         .path_segment = "bridgeId",
1130         .is_wildcard = 1,
1131         .callbacks = {
1132                 [AST_HTTP_GET] = ast_ari_bridges_get_cb,
1133                 [AST_HTTP_DELETE] = ast_ari_bridges_destroy_cb,
1134         },
1135         .num_children = 5,
1136         .children = { &bridges_bridgeId_addChannel,&bridges_bridgeId_removeChannel,&bridges_bridgeId_moh,&bridges_bridgeId_play,&bridges_bridgeId_record, }
1137 };
1138 /*! \brief REST handler for /api-docs/bridges.{format} */
1139 static struct stasis_rest_handlers bridges = {
1140         .path_segment = "bridges",
1141         .callbacks = {
1142                 [AST_HTTP_GET] = ast_ari_bridges_list_cb,
1143                 [AST_HTTP_POST] = ast_ari_bridges_create_cb,
1144         },
1145         .num_children = 1,
1146         .children = { &bridges_bridgeId, }
1147 };
1148
1149 static int load_module(void)
1150 {
1151         int res = 0;
1152         stasis_app_ref();
1153         res |= ast_ari_add_handler(&bridges);
1154         return res;
1155 }
1156
1157 static int unload_module(void)
1158 {
1159         ast_ari_remove_handler(&bridges);
1160         stasis_app_unref();
1161         return 0;
1162 }
1163
1164 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Bridge resources",
1165         .load = load_module,
1166         .unload = unload_module,
1167         .nonoptreq = "res_ari,res_stasis",
1168         );