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