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