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