res_pjsip res_pjsip_mwi: Misc fixes and cleanups.
[asterisk/asterisk.git] / res / res_ari_channels.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 Channel resources
30  *
31  * \author David M. Lee, II <dlee@digium.com>
32  */
33
34 /*** MODULEINFO
35         <depend type="module">res_ari</depend>
36         <depend type="module">res_ari_model</depend>
37         <depend type="module">res_stasis</depend>
38         <support_level>core</support_level>
39  ***/
40
41 #include "asterisk.h"
42
43 ASTERISK_REGISTER_FILE()
44
45 #include "asterisk/app.h"
46 #include "asterisk/module.h"
47 #include "asterisk/stasis_app.h"
48 #include "ari/resource_channels.h"
49 #if defined(AST_DEVMODE)
50 #include "ari/ari_model_validators.h"
51 #endif
52
53 #define MAX_VALS 128
54
55 /*!
56  * \brief Parameter parsing callback for /channels.
57  * \param get_params GET parameters in the HTTP request.
58  * \param path_vars Path variables extracted from the request.
59  * \param headers HTTP headers.
60  * \param[out] response Response to the HTTP request.
61  */
62 static void ast_ari_channels_list_cb(
63         struct ast_tcptls_session_instance *ser,
64         struct ast_variable *get_params, struct ast_variable *path_vars,
65         struct ast_variable *headers, struct ast_ari_response *response)
66 {
67         struct ast_ari_channels_list_args args = {};
68         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
69 #if defined(AST_DEVMODE)
70         int is_valid;
71         int code;
72 #endif /* AST_DEVMODE */
73
74         ast_ari_channels_list(headers, &args, response);
75 #if defined(AST_DEVMODE)
76         code = response->response_code;
77
78         switch (code) {
79         case 0: /* Implementation is still a stub, or the code wasn't set */
80                 is_valid = response->message == NULL;
81                 break;
82         case 500: /* Internal Server Error */
83         case 501: /* Not Implemented */
84                 is_valid = 1;
85                 break;
86         default:
87                 if (200 <= code && code <= 299) {
88                         is_valid = ast_ari_validate_list(response->message,
89                                 ast_ari_validate_channel_fn());
90                 } else {
91                         ast_log(LOG_ERROR, "Invalid error response %d for /channels\n", code);
92                         is_valid = 0;
93                 }
94         }
95
96         if (!is_valid) {
97                 ast_log(LOG_ERROR, "Response validation failed for /channels\n");
98                 ast_ari_response_error(response, 500,
99                         "Internal Server Error", "Response validation failed");
100         }
101 #endif /* AST_DEVMODE */
102
103 fin: __attribute__((unused))
104         return;
105 }
106 int ast_ari_channels_originate_parse_body(
107         struct ast_json *body,
108         struct ast_ari_channels_originate_args *args)
109 {
110         struct ast_json *field;
111         /* Parse query parameters out of it */
112         field = ast_json_object_get(body, "endpoint");
113         if (field) {
114                 args->endpoint = ast_json_string_get(field);
115         }
116         field = ast_json_object_get(body, "extension");
117         if (field) {
118                 args->extension = ast_json_string_get(field);
119         }
120         field = ast_json_object_get(body, "context");
121         if (field) {
122                 args->context = ast_json_string_get(field);
123         }
124         field = ast_json_object_get(body, "priority");
125         if (field) {
126                 args->priority = ast_json_integer_get(field);
127         }
128         field = ast_json_object_get(body, "label");
129         if (field) {
130                 args->label = ast_json_string_get(field);
131         }
132         field = ast_json_object_get(body, "app");
133         if (field) {
134                 args->app = ast_json_string_get(field);
135         }
136         field = ast_json_object_get(body, "appArgs");
137         if (field) {
138                 args->app_args = ast_json_string_get(field);
139         }
140         field = ast_json_object_get(body, "callerId");
141         if (field) {
142                 args->caller_id = ast_json_string_get(field);
143         }
144         field = ast_json_object_get(body, "timeout");
145         if (field) {
146                 args->timeout = ast_json_integer_get(field);
147         }
148         field = ast_json_object_get(body, "channelId");
149         if (field) {
150                 args->channel_id = ast_json_string_get(field);
151         }
152         field = ast_json_object_get(body, "otherChannelId");
153         if (field) {
154                 args->other_channel_id = ast_json_string_get(field);
155         }
156         field = ast_json_object_get(body, "originator");
157         if (field) {
158                 args->originator = ast_json_string_get(field);
159         }
160         field = ast_json_object_get(body, "formats");
161         if (field) {
162                 args->formats = ast_json_string_get(field);
163         }
164         return 0;
165 }
166
167 /*!
168  * \brief Parameter parsing callback for /channels.
169  * \param get_params GET parameters in the HTTP request.
170  * \param path_vars Path variables extracted from the request.
171  * \param headers HTTP headers.
172  * \param[out] response Response to the HTTP request.
173  */
174 static void ast_ari_channels_originate_cb(
175         struct ast_tcptls_session_instance *ser,
176         struct ast_variable *get_params, struct ast_variable *path_vars,
177         struct ast_variable *headers, struct ast_ari_response *response)
178 {
179         struct ast_ari_channels_originate_args args = {};
180         struct ast_variable *i;
181         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
182 #if defined(AST_DEVMODE)
183         int is_valid;
184         int code;
185 #endif /* AST_DEVMODE */
186
187         for (i = get_params; i; i = i->next) {
188                 if (strcmp(i->name, "endpoint") == 0) {
189                         args.endpoint = (i->value);
190                 } else
191                 if (strcmp(i->name, "extension") == 0) {
192                         args.extension = (i->value);
193                 } else
194                 if (strcmp(i->name, "context") == 0) {
195                         args.context = (i->value);
196                 } else
197                 if (strcmp(i->name, "priority") == 0) {
198                         args.priority = atol(i->value);
199                 } else
200                 if (strcmp(i->name, "label") == 0) {
201                         args.label = (i->value);
202                 } else
203                 if (strcmp(i->name, "app") == 0) {
204                         args.app = (i->value);
205                 } else
206                 if (strcmp(i->name, "appArgs") == 0) {
207                         args.app_args = (i->value);
208                 } else
209                 if (strcmp(i->name, "callerId") == 0) {
210                         args.caller_id = (i->value);
211                 } else
212                 if (strcmp(i->name, "timeout") == 0) {
213                         args.timeout = atoi(i->value);
214                 } else
215                 if (strcmp(i->name, "channelId") == 0) {
216                         args.channel_id = (i->value);
217                 } else
218                 if (strcmp(i->name, "otherChannelId") == 0) {
219                         args.other_channel_id = (i->value);
220                 } else
221                 if (strcmp(i->name, "originator") == 0) {
222                         args.originator = (i->value);
223                 } else
224                 if (strcmp(i->name, "formats") == 0) {
225                         args.formats = (i->value);
226                 } else
227                 {}
228         }
229         /* Look for a JSON request entity */
230         body = ast_http_get_json(ser, headers);
231         if (!body) {
232                 switch (errno) {
233                 case EFBIG:
234                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
235                         goto fin;
236                 case ENOMEM:
237                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
238                         goto fin;
239                 case EIO:
240                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
241                         goto fin;
242                 }
243         }
244         args.variables = body;
245         ast_ari_channels_originate(headers, &args, response);
246 #if defined(AST_DEVMODE)
247         code = response->response_code;
248
249         switch (code) {
250         case 0: /* Implementation is still a stub, or the code wasn't set */
251                 is_valid = response->message == NULL;
252                 break;
253         case 500: /* Internal Server Error */
254         case 501: /* Not Implemented */
255         case 400: /* Invalid parameters for originating a channel. */
256                 is_valid = 1;
257                 break;
258         default:
259                 if (200 <= code && code <= 299) {
260                         is_valid = ast_ari_validate_channel(
261                                 response->message);
262                 } else {
263                         ast_log(LOG_ERROR, "Invalid error response %d for /channels\n", code);
264                         is_valid = 0;
265                 }
266         }
267
268         if (!is_valid) {
269                 ast_log(LOG_ERROR, "Response validation failed for /channels\n");
270                 ast_ari_response_error(response, 500,
271                         "Internal Server Error", "Response validation failed");
272         }
273 #endif /* AST_DEVMODE */
274
275 fin: __attribute__((unused))
276         return;
277 }
278 int ast_ari_channels_create_parse_body(
279         struct ast_json *body,
280         struct ast_ari_channels_create_args *args)
281 {
282         struct ast_json *field;
283         /* Parse query parameters out of it */
284         field = ast_json_object_get(body, "endpoint");
285         if (field) {
286                 args->endpoint = ast_json_string_get(field);
287         }
288         field = ast_json_object_get(body, "app");
289         if (field) {
290                 args->app = ast_json_string_get(field);
291         }
292         field = ast_json_object_get(body, "appArgs");
293         if (field) {
294                 args->app_args = ast_json_string_get(field);
295         }
296         field = ast_json_object_get(body, "channelId");
297         if (field) {
298                 args->channel_id = ast_json_string_get(field);
299         }
300         field = ast_json_object_get(body, "otherChannelId");
301         if (field) {
302                 args->other_channel_id = ast_json_string_get(field);
303         }
304         field = ast_json_object_get(body, "originator");
305         if (field) {
306                 args->originator = ast_json_string_get(field);
307         }
308         field = ast_json_object_get(body, "formats");
309         if (field) {
310                 args->formats = ast_json_string_get(field);
311         }
312         return 0;
313 }
314
315 /*!
316  * \brief Parameter parsing callback for /channels/create.
317  * \param get_params GET parameters in the HTTP request.
318  * \param path_vars Path variables extracted from the request.
319  * \param headers HTTP headers.
320  * \param[out] response Response to the HTTP request.
321  */
322 static void ast_ari_channels_create_cb(
323         struct ast_tcptls_session_instance *ser,
324         struct ast_variable *get_params, struct ast_variable *path_vars,
325         struct ast_variable *headers, struct ast_ari_response *response)
326 {
327         struct ast_ari_channels_create_args args = {};
328         struct ast_variable *i;
329         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
330 #if defined(AST_DEVMODE)
331         int is_valid;
332         int code;
333 #endif /* AST_DEVMODE */
334
335         for (i = get_params; i; i = i->next) {
336                 if (strcmp(i->name, "endpoint") == 0) {
337                         args.endpoint = (i->value);
338                 } else
339                 if (strcmp(i->name, "app") == 0) {
340                         args.app = (i->value);
341                 } else
342                 if (strcmp(i->name, "appArgs") == 0) {
343                         args.app_args = (i->value);
344                 } else
345                 if (strcmp(i->name, "channelId") == 0) {
346                         args.channel_id = (i->value);
347                 } else
348                 if (strcmp(i->name, "otherChannelId") == 0) {
349                         args.other_channel_id = (i->value);
350                 } else
351                 if (strcmp(i->name, "originator") == 0) {
352                         args.originator = (i->value);
353                 } else
354                 if (strcmp(i->name, "formats") == 0) {
355                         args.formats = (i->value);
356                 } else
357                 {}
358         }
359         /* Look for a JSON request entity */
360         body = ast_http_get_json(ser, headers);
361         if (!body) {
362                 switch (errno) {
363                 case EFBIG:
364                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
365                         goto fin;
366                 case ENOMEM:
367                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
368                         goto fin;
369                 case EIO:
370                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
371                         goto fin;
372                 }
373         }
374         if (ast_ari_channels_create_parse_body(body, &args)) {
375                 ast_ari_response_alloc_failed(response);
376                 goto fin;
377         }
378         ast_ari_channels_create(headers, &args, response);
379 #if defined(AST_DEVMODE)
380         code = response->response_code;
381
382         switch (code) {
383         case 0: /* Implementation is still a stub, or the code wasn't set */
384                 is_valid = response->message == NULL;
385                 break;
386         case 500: /* Internal Server Error */
387         case 501: /* Not Implemented */
388                 is_valid = 1;
389                 break;
390         default:
391                 if (200 <= code && code <= 299) {
392                         is_valid = ast_ari_validate_channel(
393                                 response->message);
394                 } else {
395                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/create\n", code);
396                         is_valid = 0;
397                 }
398         }
399
400         if (!is_valid) {
401                 ast_log(LOG_ERROR, "Response validation failed for /channels/create\n");
402                 ast_ari_response_error(response, 500,
403                         "Internal Server Error", "Response validation failed");
404         }
405 #endif /* AST_DEVMODE */
406
407 fin: __attribute__((unused))
408         return;
409 }
410 /*!
411  * \brief Parameter parsing callback for /channels/{channelId}.
412  * \param get_params GET parameters in the HTTP request.
413  * \param path_vars Path variables extracted from the request.
414  * \param headers HTTP headers.
415  * \param[out] response Response to the HTTP request.
416  */
417 static void ast_ari_channels_get_cb(
418         struct ast_tcptls_session_instance *ser,
419         struct ast_variable *get_params, struct ast_variable *path_vars,
420         struct ast_variable *headers, struct ast_ari_response *response)
421 {
422         struct ast_ari_channels_get_args args = {};
423         struct ast_variable *i;
424         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
425 #if defined(AST_DEVMODE)
426         int is_valid;
427         int code;
428 #endif /* AST_DEVMODE */
429
430         for (i = path_vars; i; i = i->next) {
431                 if (strcmp(i->name, "channelId") == 0) {
432                         args.channel_id = (i->value);
433                 } else
434                 {}
435         }
436         ast_ari_channels_get(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 404: /* Channel not found */
447                 is_valid = 1;
448                 break;
449         default:
450                 if (200 <= code && code <= 299) {
451                         is_valid = ast_ari_validate_channel(
452                                 response->message);
453                 } else {
454                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}\n", code);
455                         is_valid = 0;
456                 }
457         }
458
459         if (!is_valid) {
460                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}\n");
461                 ast_ari_response_error(response, 500,
462                         "Internal Server Error", "Response validation failed");
463         }
464 #endif /* AST_DEVMODE */
465
466 fin: __attribute__((unused))
467         return;
468 }
469 int ast_ari_channels_originate_with_id_parse_body(
470         struct ast_json *body,
471         struct ast_ari_channels_originate_with_id_args *args)
472 {
473         struct ast_json *field;
474         /* Parse query parameters out of it */
475         field = ast_json_object_get(body, "endpoint");
476         if (field) {
477                 args->endpoint = ast_json_string_get(field);
478         }
479         field = ast_json_object_get(body, "extension");
480         if (field) {
481                 args->extension = ast_json_string_get(field);
482         }
483         field = ast_json_object_get(body, "context");
484         if (field) {
485                 args->context = ast_json_string_get(field);
486         }
487         field = ast_json_object_get(body, "priority");
488         if (field) {
489                 args->priority = ast_json_integer_get(field);
490         }
491         field = ast_json_object_get(body, "label");
492         if (field) {
493                 args->label = ast_json_string_get(field);
494         }
495         field = ast_json_object_get(body, "app");
496         if (field) {
497                 args->app = ast_json_string_get(field);
498         }
499         field = ast_json_object_get(body, "appArgs");
500         if (field) {
501                 args->app_args = ast_json_string_get(field);
502         }
503         field = ast_json_object_get(body, "callerId");
504         if (field) {
505                 args->caller_id = ast_json_string_get(field);
506         }
507         field = ast_json_object_get(body, "timeout");
508         if (field) {
509                 args->timeout = ast_json_integer_get(field);
510         }
511         field = ast_json_object_get(body, "otherChannelId");
512         if (field) {
513                 args->other_channel_id = ast_json_string_get(field);
514         }
515         field = ast_json_object_get(body, "originator");
516         if (field) {
517                 args->originator = ast_json_string_get(field);
518         }
519         field = ast_json_object_get(body, "formats");
520         if (field) {
521                 args->formats = ast_json_string_get(field);
522         }
523         return 0;
524 }
525
526 /*!
527  * \brief Parameter parsing callback for /channels/{channelId}.
528  * \param get_params GET parameters in the HTTP request.
529  * \param path_vars Path variables extracted from the request.
530  * \param headers HTTP headers.
531  * \param[out] response Response to the HTTP request.
532  */
533 static void ast_ari_channels_originate_with_id_cb(
534         struct ast_tcptls_session_instance *ser,
535         struct ast_variable *get_params, struct ast_variable *path_vars,
536         struct ast_variable *headers, struct ast_ari_response *response)
537 {
538         struct ast_ari_channels_originate_with_id_args args = {};
539         struct ast_variable *i;
540         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
541 #if defined(AST_DEVMODE)
542         int is_valid;
543         int code;
544 #endif /* AST_DEVMODE */
545
546         for (i = get_params; i; i = i->next) {
547                 if (strcmp(i->name, "endpoint") == 0) {
548                         args.endpoint = (i->value);
549                 } else
550                 if (strcmp(i->name, "extension") == 0) {
551                         args.extension = (i->value);
552                 } else
553                 if (strcmp(i->name, "context") == 0) {
554                         args.context = (i->value);
555                 } else
556                 if (strcmp(i->name, "priority") == 0) {
557                         args.priority = atol(i->value);
558                 } else
559                 if (strcmp(i->name, "label") == 0) {
560                         args.label = (i->value);
561                 } else
562                 if (strcmp(i->name, "app") == 0) {
563                         args.app = (i->value);
564                 } else
565                 if (strcmp(i->name, "appArgs") == 0) {
566                         args.app_args = (i->value);
567                 } else
568                 if (strcmp(i->name, "callerId") == 0) {
569                         args.caller_id = (i->value);
570                 } else
571                 if (strcmp(i->name, "timeout") == 0) {
572                         args.timeout = atoi(i->value);
573                 } else
574                 if (strcmp(i->name, "otherChannelId") == 0) {
575                         args.other_channel_id = (i->value);
576                 } else
577                 if (strcmp(i->name, "originator") == 0) {
578                         args.originator = (i->value);
579                 } else
580                 if (strcmp(i->name, "formats") == 0) {
581                         args.formats = (i->value);
582                 } else
583                 {}
584         }
585         for (i = path_vars; i; i = i->next) {
586                 if (strcmp(i->name, "channelId") == 0) {
587                         args.channel_id = (i->value);
588                 } else
589                 {}
590         }
591         /* Look for a JSON request entity */
592         body = ast_http_get_json(ser, headers);
593         if (!body) {
594                 switch (errno) {
595                 case EFBIG:
596                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
597                         goto fin;
598                 case ENOMEM:
599                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
600                         goto fin;
601                 case EIO:
602                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
603                         goto fin;
604                 }
605         }
606         args.variables = body;
607         ast_ari_channels_originate_with_id(headers, &args, response);
608 #if defined(AST_DEVMODE)
609         code = response->response_code;
610
611         switch (code) {
612         case 0: /* Implementation is still a stub, or the code wasn't set */
613                 is_valid = response->message == NULL;
614                 break;
615         case 500: /* Internal Server Error */
616         case 501: /* Not Implemented */
617         case 400: /* Invalid parameters for originating a channel. */
618                 is_valid = 1;
619                 break;
620         default:
621                 if (200 <= code && code <= 299) {
622                         is_valid = ast_ari_validate_channel(
623                                 response->message);
624                 } else {
625                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}\n", code);
626                         is_valid = 0;
627                 }
628         }
629
630         if (!is_valid) {
631                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}\n");
632                 ast_ari_response_error(response, 500,
633                         "Internal Server Error", "Response validation failed");
634         }
635 #endif /* AST_DEVMODE */
636
637 fin: __attribute__((unused))
638         return;
639 }
640 int ast_ari_channels_hangup_parse_body(
641         struct ast_json *body,
642         struct ast_ari_channels_hangup_args *args)
643 {
644         struct ast_json *field;
645         /* Parse query parameters out of it */
646         field = ast_json_object_get(body, "reason");
647         if (field) {
648                 args->reason = ast_json_string_get(field);
649         }
650         return 0;
651 }
652
653 /*!
654  * \brief Parameter parsing callback for /channels/{channelId}.
655  * \param get_params GET parameters in the HTTP request.
656  * \param path_vars Path variables extracted from the request.
657  * \param headers HTTP headers.
658  * \param[out] response Response to the HTTP request.
659  */
660 static void ast_ari_channels_hangup_cb(
661         struct ast_tcptls_session_instance *ser,
662         struct ast_variable *get_params, struct ast_variable *path_vars,
663         struct ast_variable *headers, struct ast_ari_response *response)
664 {
665         struct ast_ari_channels_hangup_args args = {};
666         struct ast_variable *i;
667         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
668 #if defined(AST_DEVMODE)
669         int is_valid;
670         int code;
671 #endif /* AST_DEVMODE */
672
673         for (i = get_params; i; i = i->next) {
674                 if (strcmp(i->name, "reason") == 0) {
675                         args.reason = (i->value);
676                 } else
677                 {}
678         }
679         for (i = path_vars; i; i = i->next) {
680                 if (strcmp(i->name, "channelId") == 0) {
681                         args.channel_id = (i->value);
682                 } else
683                 {}
684         }
685         /* Look for a JSON request entity */
686         body = ast_http_get_json(ser, headers);
687         if (!body) {
688                 switch (errno) {
689                 case EFBIG:
690                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
691                         goto fin;
692                 case ENOMEM:
693                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
694                         goto fin;
695                 case EIO:
696                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
697                         goto fin;
698                 }
699         }
700         if (ast_ari_channels_hangup_parse_body(body, &args)) {
701                 ast_ari_response_alloc_failed(response);
702                 goto fin;
703         }
704         ast_ari_channels_hangup(headers, &args, response);
705 #if defined(AST_DEVMODE)
706         code = response->response_code;
707
708         switch (code) {
709         case 0: /* Implementation is still a stub, or the code wasn't set */
710                 is_valid = response->message == NULL;
711                 break;
712         case 500: /* Internal Server Error */
713         case 501: /* Not Implemented */
714         case 400: /* Invalid reason for hangup provided */
715         case 404: /* Channel not found */
716                 is_valid = 1;
717                 break;
718         default:
719                 if (200 <= code && code <= 299) {
720                         is_valid = ast_ari_validate_void(
721                                 response->message);
722                 } else {
723                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}\n", code);
724                         is_valid = 0;
725                 }
726         }
727
728         if (!is_valid) {
729                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}\n");
730                 ast_ari_response_error(response, 500,
731                         "Internal Server Error", "Response validation failed");
732         }
733 #endif /* AST_DEVMODE */
734
735 fin: __attribute__((unused))
736         return;
737 }
738 int ast_ari_channels_continue_in_dialplan_parse_body(
739         struct ast_json *body,
740         struct ast_ari_channels_continue_in_dialplan_args *args)
741 {
742         struct ast_json *field;
743         /* Parse query parameters out of it */
744         field = ast_json_object_get(body, "context");
745         if (field) {
746                 args->context = ast_json_string_get(field);
747         }
748         field = ast_json_object_get(body, "extension");
749         if (field) {
750                 args->extension = ast_json_string_get(field);
751         }
752         field = ast_json_object_get(body, "priority");
753         if (field) {
754                 args->priority = ast_json_integer_get(field);
755         }
756         field = ast_json_object_get(body, "label");
757         if (field) {
758                 args->label = ast_json_string_get(field);
759         }
760         return 0;
761 }
762
763 /*!
764  * \brief Parameter parsing callback for /channels/{channelId}/continue.
765  * \param get_params GET parameters in the HTTP request.
766  * \param path_vars Path variables extracted from the request.
767  * \param headers HTTP headers.
768  * \param[out] response Response to the HTTP request.
769  */
770 static void ast_ari_channels_continue_in_dialplan_cb(
771         struct ast_tcptls_session_instance *ser,
772         struct ast_variable *get_params, struct ast_variable *path_vars,
773         struct ast_variable *headers, struct ast_ari_response *response)
774 {
775         struct ast_ari_channels_continue_in_dialplan_args args = {};
776         struct ast_variable *i;
777         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
778 #if defined(AST_DEVMODE)
779         int is_valid;
780         int code;
781 #endif /* AST_DEVMODE */
782
783         for (i = get_params; i; i = i->next) {
784                 if (strcmp(i->name, "context") == 0) {
785                         args.context = (i->value);
786                 } else
787                 if (strcmp(i->name, "extension") == 0) {
788                         args.extension = (i->value);
789                 } else
790                 if (strcmp(i->name, "priority") == 0) {
791                         args.priority = atoi(i->value);
792                 } else
793                 if (strcmp(i->name, "label") == 0) {
794                         args.label = (i->value);
795                 } else
796                 {}
797         }
798         for (i = path_vars; i; i = i->next) {
799                 if (strcmp(i->name, "channelId") == 0) {
800                         args.channel_id = (i->value);
801                 } else
802                 {}
803         }
804         /* Look for a JSON request entity */
805         body = ast_http_get_json(ser, headers);
806         if (!body) {
807                 switch (errno) {
808                 case EFBIG:
809                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
810                         goto fin;
811                 case ENOMEM:
812                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
813                         goto fin;
814                 case EIO:
815                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
816                         goto fin;
817                 }
818         }
819         if (ast_ari_channels_continue_in_dialplan_parse_body(body, &args)) {
820                 ast_ari_response_alloc_failed(response);
821                 goto fin;
822         }
823         ast_ari_channels_continue_in_dialplan(headers, &args, response);
824 #if defined(AST_DEVMODE)
825         code = response->response_code;
826
827         switch (code) {
828         case 0: /* Implementation is still a stub, or the code wasn't set */
829                 is_valid = response->message == NULL;
830                 break;
831         case 500: /* Internal Server Error */
832         case 501: /* Not Implemented */
833         case 404: /* Channel not found */
834         case 409: /* Channel not in a Stasis application */
835         case 412: /* Channel in invalid state */
836                 is_valid = 1;
837                 break;
838         default:
839                 if (200 <= code && code <= 299) {
840                         is_valid = ast_ari_validate_void(
841                                 response->message);
842                 } else {
843                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/continue\n", code);
844                         is_valid = 0;
845                 }
846         }
847
848         if (!is_valid) {
849                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/continue\n");
850                 ast_ari_response_error(response, 500,
851                         "Internal Server Error", "Response validation failed");
852         }
853 #endif /* AST_DEVMODE */
854
855 fin: __attribute__((unused))
856         return;
857 }
858 int ast_ari_channels_redirect_parse_body(
859         struct ast_json *body,
860         struct ast_ari_channels_redirect_args *args)
861 {
862         struct ast_json *field;
863         /* Parse query parameters out of it */
864         field = ast_json_object_get(body, "endpoint");
865         if (field) {
866                 args->endpoint = ast_json_string_get(field);
867         }
868         return 0;
869 }
870
871 /*!
872  * \brief Parameter parsing callback for /channels/{channelId}/redirect.
873  * \param get_params GET parameters in the HTTP request.
874  * \param path_vars Path variables extracted from the request.
875  * \param headers HTTP headers.
876  * \param[out] response Response to the HTTP request.
877  */
878 static void ast_ari_channels_redirect_cb(
879         struct ast_tcptls_session_instance *ser,
880         struct ast_variable *get_params, struct ast_variable *path_vars,
881         struct ast_variable *headers, struct ast_ari_response *response)
882 {
883         struct ast_ari_channels_redirect_args args = {};
884         struct ast_variable *i;
885         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
886 #if defined(AST_DEVMODE)
887         int is_valid;
888         int code;
889 #endif /* AST_DEVMODE */
890
891         for (i = get_params; i; i = i->next) {
892                 if (strcmp(i->name, "endpoint") == 0) {
893                         args.endpoint = (i->value);
894                 } else
895                 {}
896         }
897         for (i = path_vars; i; i = i->next) {
898                 if (strcmp(i->name, "channelId") == 0) {
899                         args.channel_id = (i->value);
900                 } else
901                 {}
902         }
903         /* Look for a JSON request entity */
904         body = ast_http_get_json(ser, headers);
905         if (!body) {
906                 switch (errno) {
907                 case EFBIG:
908                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
909                         goto fin;
910                 case ENOMEM:
911                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
912                         goto fin;
913                 case EIO:
914                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
915                         goto fin;
916                 }
917         }
918         if (ast_ari_channels_redirect_parse_body(body, &args)) {
919                 ast_ari_response_alloc_failed(response);
920                 goto fin;
921         }
922         ast_ari_channels_redirect(headers, &args, response);
923 #if defined(AST_DEVMODE)
924         code = response->response_code;
925
926         switch (code) {
927         case 0: /* Implementation is still a stub, or the code wasn't set */
928                 is_valid = response->message == NULL;
929                 break;
930         case 500: /* Internal Server Error */
931         case 501: /* Not Implemented */
932         case 400: /* Endpoint parameter not provided */
933         case 404: /* Channel or endpoint not found */
934         case 409: /* Channel not in a Stasis application */
935         case 422: /* Endpoint is not the same type as the channel */
936         case 412: /* Channel in invalid state */
937                 is_valid = 1;
938                 break;
939         default:
940                 if (200 <= code && code <= 299) {
941                         is_valid = ast_ari_validate_void(
942                                 response->message);
943                 } else {
944                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/redirect\n", code);
945                         is_valid = 0;
946                 }
947         }
948
949         if (!is_valid) {
950                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/redirect\n");
951                 ast_ari_response_error(response, 500,
952                         "Internal Server Error", "Response validation failed");
953         }
954 #endif /* AST_DEVMODE */
955
956 fin: __attribute__((unused))
957         return;
958 }
959 /*!
960  * \brief Parameter parsing callback for /channels/{channelId}/answer.
961  * \param get_params GET parameters in the HTTP request.
962  * \param path_vars Path variables extracted from the request.
963  * \param headers HTTP headers.
964  * \param[out] response Response to the HTTP request.
965  */
966 static void ast_ari_channels_answer_cb(
967         struct ast_tcptls_session_instance *ser,
968         struct ast_variable *get_params, struct ast_variable *path_vars,
969         struct ast_variable *headers, struct ast_ari_response *response)
970 {
971         struct ast_ari_channels_answer_args args = {};
972         struct ast_variable *i;
973         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
974 #if defined(AST_DEVMODE)
975         int is_valid;
976         int code;
977 #endif /* AST_DEVMODE */
978
979         for (i = path_vars; i; i = i->next) {
980                 if (strcmp(i->name, "channelId") == 0) {
981                         args.channel_id = (i->value);
982                 } else
983                 {}
984         }
985         ast_ari_channels_answer(headers, &args, response);
986 #if defined(AST_DEVMODE)
987         code = response->response_code;
988
989         switch (code) {
990         case 0: /* Implementation is still a stub, or the code wasn't set */
991                 is_valid = response->message == NULL;
992                 break;
993         case 500: /* Internal Server Error */
994         case 501: /* Not Implemented */
995         case 404: /* Channel not found */
996         case 409: /* Channel not in a Stasis application */
997         case 412: /* Channel in invalid state */
998                 is_valid = 1;
999                 break;
1000         default:
1001                 if (200 <= code && code <= 299) {
1002                         is_valid = ast_ari_validate_void(
1003                                 response->message);
1004                 } else {
1005                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/answer\n", code);
1006                         is_valid = 0;
1007                 }
1008         }
1009
1010         if (!is_valid) {
1011                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/answer\n");
1012                 ast_ari_response_error(response, 500,
1013                         "Internal Server Error", "Response validation failed");
1014         }
1015 #endif /* AST_DEVMODE */
1016
1017 fin: __attribute__((unused))
1018         return;
1019 }
1020 /*!
1021  * \brief Parameter parsing callback for /channels/{channelId}/ring.
1022  * \param get_params GET parameters in the HTTP request.
1023  * \param path_vars Path variables extracted from the request.
1024  * \param headers HTTP headers.
1025  * \param[out] response Response to the HTTP request.
1026  */
1027 static void ast_ari_channels_ring_cb(
1028         struct ast_tcptls_session_instance *ser,
1029         struct ast_variable *get_params, struct ast_variable *path_vars,
1030         struct ast_variable *headers, struct ast_ari_response *response)
1031 {
1032         struct ast_ari_channels_ring_args args = {};
1033         struct ast_variable *i;
1034         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1035 #if defined(AST_DEVMODE)
1036         int is_valid;
1037         int code;
1038 #endif /* AST_DEVMODE */
1039
1040         for (i = path_vars; i; i = i->next) {
1041                 if (strcmp(i->name, "channelId") == 0) {
1042                         args.channel_id = (i->value);
1043                 } else
1044                 {}
1045         }
1046         ast_ari_channels_ring(headers, &args, response);
1047 #if defined(AST_DEVMODE)
1048         code = response->response_code;
1049
1050         switch (code) {
1051         case 0: /* Implementation is still a stub, or the code wasn't set */
1052                 is_valid = response->message == NULL;
1053                 break;
1054         case 500: /* Internal Server Error */
1055         case 501: /* Not Implemented */
1056         case 404: /* Channel not found */
1057         case 409: /* Channel not in a Stasis application */
1058         case 412: /* Channel in invalid state */
1059                 is_valid = 1;
1060                 break;
1061         default:
1062                 if (200 <= code && code <= 299) {
1063                         is_valid = ast_ari_validate_void(
1064                                 response->message);
1065                 } else {
1066                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/ring\n", code);
1067                         is_valid = 0;
1068                 }
1069         }
1070
1071         if (!is_valid) {
1072                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/ring\n");
1073                 ast_ari_response_error(response, 500,
1074                         "Internal Server Error", "Response validation failed");
1075         }
1076 #endif /* AST_DEVMODE */
1077
1078 fin: __attribute__((unused))
1079         return;
1080 }
1081 /*!
1082  * \brief Parameter parsing callback for /channels/{channelId}/ring.
1083  * \param get_params GET parameters in the HTTP request.
1084  * \param path_vars Path variables extracted from the request.
1085  * \param headers HTTP headers.
1086  * \param[out] response Response to the HTTP request.
1087  */
1088 static void ast_ari_channels_ring_stop_cb(
1089         struct ast_tcptls_session_instance *ser,
1090         struct ast_variable *get_params, struct ast_variable *path_vars,
1091         struct ast_variable *headers, struct ast_ari_response *response)
1092 {
1093         struct ast_ari_channels_ring_stop_args args = {};
1094         struct ast_variable *i;
1095         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1096 #if defined(AST_DEVMODE)
1097         int is_valid;
1098         int code;
1099 #endif /* AST_DEVMODE */
1100
1101         for (i = path_vars; i; i = i->next) {
1102                 if (strcmp(i->name, "channelId") == 0) {
1103                         args.channel_id = (i->value);
1104                 } else
1105                 {}
1106         }
1107         ast_ari_channels_ring_stop(headers, &args, response);
1108 #if defined(AST_DEVMODE)
1109         code = response->response_code;
1110
1111         switch (code) {
1112         case 0: /* Implementation is still a stub, or the code wasn't set */
1113                 is_valid = response->message == NULL;
1114                 break;
1115         case 500: /* Internal Server Error */
1116         case 501: /* Not Implemented */
1117         case 404: /* Channel not found */
1118         case 409: /* Channel not in a Stasis application */
1119         case 412: /* Channel in invalid state */
1120                 is_valid = 1;
1121                 break;
1122         default:
1123                 if (200 <= code && code <= 299) {
1124                         is_valid = ast_ari_validate_void(
1125                                 response->message);
1126                 } else {
1127                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/ring\n", code);
1128                         is_valid = 0;
1129                 }
1130         }
1131
1132         if (!is_valid) {
1133                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/ring\n");
1134                 ast_ari_response_error(response, 500,
1135                         "Internal Server Error", "Response validation failed");
1136         }
1137 #endif /* AST_DEVMODE */
1138
1139 fin: __attribute__((unused))
1140         return;
1141 }
1142 int ast_ari_channels_send_dtmf_parse_body(
1143         struct ast_json *body,
1144         struct ast_ari_channels_send_dtmf_args *args)
1145 {
1146         struct ast_json *field;
1147         /* Parse query parameters out of it */
1148         field = ast_json_object_get(body, "dtmf");
1149         if (field) {
1150                 args->dtmf = ast_json_string_get(field);
1151         }
1152         field = ast_json_object_get(body, "before");
1153         if (field) {
1154                 args->before = ast_json_integer_get(field);
1155         }
1156         field = ast_json_object_get(body, "between");
1157         if (field) {
1158                 args->between = ast_json_integer_get(field);
1159         }
1160         field = ast_json_object_get(body, "duration");
1161         if (field) {
1162                 args->duration = ast_json_integer_get(field);
1163         }
1164         field = ast_json_object_get(body, "after");
1165         if (field) {
1166                 args->after = ast_json_integer_get(field);
1167         }
1168         return 0;
1169 }
1170
1171 /*!
1172  * \brief Parameter parsing callback for /channels/{channelId}/dtmf.
1173  * \param get_params GET parameters in the HTTP request.
1174  * \param path_vars Path variables extracted from the request.
1175  * \param headers HTTP headers.
1176  * \param[out] response Response to the HTTP request.
1177  */
1178 static void ast_ari_channels_send_dtmf_cb(
1179         struct ast_tcptls_session_instance *ser,
1180         struct ast_variable *get_params, struct ast_variable *path_vars,
1181         struct ast_variable *headers, struct ast_ari_response *response)
1182 {
1183         struct ast_ari_channels_send_dtmf_args args = {};
1184         struct ast_variable *i;
1185         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1186 #if defined(AST_DEVMODE)
1187         int is_valid;
1188         int code;
1189 #endif /* AST_DEVMODE */
1190
1191         for (i = get_params; i; i = i->next) {
1192                 if (strcmp(i->name, "dtmf") == 0) {
1193                         args.dtmf = (i->value);
1194                 } else
1195                 if (strcmp(i->name, "before") == 0) {
1196                         args.before = atoi(i->value);
1197                 } else
1198                 if (strcmp(i->name, "between") == 0) {
1199                         args.between = atoi(i->value);
1200                 } else
1201                 if (strcmp(i->name, "duration") == 0) {
1202                         args.duration = atoi(i->value);
1203                 } else
1204                 if (strcmp(i->name, "after") == 0) {
1205                         args.after = atoi(i->value);
1206                 } else
1207                 {}
1208         }
1209         for (i = path_vars; i; i = i->next) {
1210                 if (strcmp(i->name, "channelId") == 0) {
1211                         args.channel_id = (i->value);
1212                 } else
1213                 {}
1214         }
1215         /* Look for a JSON request entity */
1216         body = ast_http_get_json(ser, headers);
1217         if (!body) {
1218                 switch (errno) {
1219                 case EFBIG:
1220                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
1221                         goto fin;
1222                 case ENOMEM:
1223                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
1224                         goto fin;
1225                 case EIO:
1226                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
1227                         goto fin;
1228                 }
1229         }
1230         if (ast_ari_channels_send_dtmf_parse_body(body, &args)) {
1231                 ast_ari_response_alloc_failed(response);
1232                 goto fin;
1233         }
1234         ast_ari_channels_send_dtmf(headers, &args, response);
1235 #if defined(AST_DEVMODE)
1236         code = response->response_code;
1237
1238         switch (code) {
1239         case 0: /* Implementation is still a stub, or the code wasn't set */
1240                 is_valid = response->message == NULL;
1241                 break;
1242         case 500: /* Internal Server Error */
1243         case 501: /* Not Implemented */
1244         case 400: /* DTMF is required */
1245         case 404: /* Channel not found */
1246         case 409: /* Channel not in a Stasis application */
1247         case 412: /* Channel in invalid state */
1248                 is_valid = 1;
1249                 break;
1250         default:
1251                 if (200 <= code && code <= 299) {
1252                         is_valid = ast_ari_validate_void(
1253                                 response->message);
1254                 } else {
1255                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/dtmf\n", code);
1256                         is_valid = 0;
1257                 }
1258         }
1259
1260         if (!is_valid) {
1261                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/dtmf\n");
1262                 ast_ari_response_error(response, 500,
1263                         "Internal Server Error", "Response validation failed");
1264         }
1265 #endif /* AST_DEVMODE */
1266
1267 fin: __attribute__((unused))
1268         return;
1269 }
1270 int ast_ari_channels_mute_parse_body(
1271         struct ast_json *body,
1272         struct ast_ari_channels_mute_args *args)
1273 {
1274         struct ast_json *field;
1275         /* Parse query parameters out of it */
1276         field = ast_json_object_get(body, "direction");
1277         if (field) {
1278                 args->direction = ast_json_string_get(field);
1279         }
1280         return 0;
1281 }
1282
1283 /*!
1284  * \brief Parameter parsing callback for /channels/{channelId}/mute.
1285  * \param get_params GET parameters in the HTTP request.
1286  * \param path_vars Path variables extracted from the request.
1287  * \param headers HTTP headers.
1288  * \param[out] response Response to the HTTP request.
1289  */
1290 static void ast_ari_channels_mute_cb(
1291         struct ast_tcptls_session_instance *ser,
1292         struct ast_variable *get_params, struct ast_variable *path_vars,
1293         struct ast_variable *headers, struct ast_ari_response *response)
1294 {
1295         struct ast_ari_channels_mute_args args = {};
1296         struct ast_variable *i;
1297         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1298 #if defined(AST_DEVMODE)
1299         int is_valid;
1300         int code;
1301 #endif /* AST_DEVMODE */
1302
1303         for (i = get_params; i; i = i->next) {
1304                 if (strcmp(i->name, "direction") == 0) {
1305                         args.direction = (i->value);
1306                 } else
1307                 {}
1308         }
1309         for (i = path_vars; i; i = i->next) {
1310                 if (strcmp(i->name, "channelId") == 0) {
1311                         args.channel_id = (i->value);
1312                 } else
1313                 {}
1314         }
1315         /* Look for a JSON request entity */
1316         body = ast_http_get_json(ser, headers);
1317         if (!body) {
1318                 switch (errno) {
1319                 case EFBIG:
1320                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
1321                         goto fin;
1322                 case ENOMEM:
1323                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
1324                         goto fin;
1325                 case EIO:
1326                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
1327                         goto fin;
1328                 }
1329         }
1330         if (ast_ari_channels_mute_parse_body(body, &args)) {
1331                 ast_ari_response_alloc_failed(response);
1332                 goto fin;
1333         }
1334         ast_ari_channels_mute(headers, &args, response);
1335 #if defined(AST_DEVMODE)
1336         code = response->response_code;
1337
1338         switch (code) {
1339         case 0: /* Implementation is still a stub, or the code wasn't set */
1340                 is_valid = response->message == NULL;
1341                 break;
1342         case 500: /* Internal Server Error */
1343         case 501: /* Not Implemented */
1344         case 404: /* Channel not found */
1345         case 409: /* Channel not in a Stasis application */
1346         case 412: /* Channel in invalid state */
1347                 is_valid = 1;
1348                 break;
1349         default:
1350                 if (200 <= code && code <= 299) {
1351                         is_valid = ast_ari_validate_void(
1352                                 response->message);
1353                 } else {
1354                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/mute\n", code);
1355                         is_valid = 0;
1356                 }
1357         }
1358
1359         if (!is_valid) {
1360                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/mute\n");
1361                 ast_ari_response_error(response, 500,
1362                         "Internal Server Error", "Response validation failed");
1363         }
1364 #endif /* AST_DEVMODE */
1365
1366 fin: __attribute__((unused))
1367         return;
1368 }
1369 int ast_ari_channels_unmute_parse_body(
1370         struct ast_json *body,
1371         struct ast_ari_channels_unmute_args *args)
1372 {
1373         struct ast_json *field;
1374         /* Parse query parameters out of it */
1375         field = ast_json_object_get(body, "direction");
1376         if (field) {
1377                 args->direction = ast_json_string_get(field);
1378         }
1379         return 0;
1380 }
1381
1382 /*!
1383  * \brief Parameter parsing callback for /channels/{channelId}/mute.
1384  * \param get_params GET parameters in the HTTP request.
1385  * \param path_vars Path variables extracted from the request.
1386  * \param headers HTTP headers.
1387  * \param[out] response Response to the HTTP request.
1388  */
1389 static void ast_ari_channels_unmute_cb(
1390         struct ast_tcptls_session_instance *ser,
1391         struct ast_variable *get_params, struct ast_variable *path_vars,
1392         struct ast_variable *headers, struct ast_ari_response *response)
1393 {
1394         struct ast_ari_channels_unmute_args args = {};
1395         struct ast_variable *i;
1396         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1397 #if defined(AST_DEVMODE)
1398         int is_valid;
1399         int code;
1400 #endif /* AST_DEVMODE */
1401
1402         for (i = get_params; i; i = i->next) {
1403                 if (strcmp(i->name, "direction") == 0) {
1404                         args.direction = (i->value);
1405                 } else
1406                 {}
1407         }
1408         for (i = path_vars; i; i = i->next) {
1409                 if (strcmp(i->name, "channelId") == 0) {
1410                         args.channel_id = (i->value);
1411                 } else
1412                 {}
1413         }
1414         /* Look for a JSON request entity */
1415         body = ast_http_get_json(ser, headers);
1416         if (!body) {
1417                 switch (errno) {
1418                 case EFBIG:
1419                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
1420                         goto fin;
1421                 case ENOMEM:
1422                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
1423                         goto fin;
1424                 case EIO:
1425                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
1426                         goto fin;
1427                 }
1428         }
1429         if (ast_ari_channels_unmute_parse_body(body, &args)) {
1430                 ast_ari_response_alloc_failed(response);
1431                 goto fin;
1432         }
1433         ast_ari_channels_unmute(headers, &args, response);
1434 #if defined(AST_DEVMODE)
1435         code = response->response_code;
1436
1437         switch (code) {
1438         case 0: /* Implementation is still a stub, or the code wasn't set */
1439                 is_valid = response->message == NULL;
1440                 break;
1441         case 500: /* Internal Server Error */
1442         case 501: /* Not Implemented */
1443         case 404: /* Channel not found */
1444         case 409: /* Channel not in a Stasis application */
1445         case 412: /* Channel in invalid state */
1446                 is_valid = 1;
1447                 break;
1448         default:
1449                 if (200 <= code && code <= 299) {
1450                         is_valid = ast_ari_validate_void(
1451                                 response->message);
1452                 } else {
1453                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/mute\n", code);
1454                         is_valid = 0;
1455                 }
1456         }
1457
1458         if (!is_valid) {
1459                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/mute\n");
1460                 ast_ari_response_error(response, 500,
1461                         "Internal Server Error", "Response validation failed");
1462         }
1463 #endif /* AST_DEVMODE */
1464
1465 fin: __attribute__((unused))
1466         return;
1467 }
1468 /*!
1469  * \brief Parameter parsing callback for /channels/{channelId}/hold.
1470  * \param get_params GET parameters in the HTTP request.
1471  * \param path_vars Path variables extracted from the request.
1472  * \param headers HTTP headers.
1473  * \param[out] response Response to the HTTP request.
1474  */
1475 static void ast_ari_channels_hold_cb(
1476         struct ast_tcptls_session_instance *ser,
1477         struct ast_variable *get_params, struct ast_variable *path_vars,
1478         struct ast_variable *headers, struct ast_ari_response *response)
1479 {
1480         struct ast_ari_channels_hold_args args = {};
1481         struct ast_variable *i;
1482         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1483 #if defined(AST_DEVMODE)
1484         int is_valid;
1485         int code;
1486 #endif /* AST_DEVMODE */
1487
1488         for (i = path_vars; i; i = i->next) {
1489                 if (strcmp(i->name, "channelId") == 0) {
1490                         args.channel_id = (i->value);
1491                 } else
1492                 {}
1493         }
1494         ast_ari_channels_hold(headers, &args, response);
1495 #if defined(AST_DEVMODE)
1496         code = response->response_code;
1497
1498         switch (code) {
1499         case 0: /* Implementation is still a stub, or the code wasn't set */
1500                 is_valid = response->message == NULL;
1501                 break;
1502         case 500: /* Internal Server Error */
1503         case 501: /* Not Implemented */
1504         case 404: /* Channel not found */
1505         case 409: /* Channel not in a Stasis application */
1506         case 412: /* Channel in invalid state */
1507                 is_valid = 1;
1508                 break;
1509         default:
1510                 if (200 <= code && code <= 299) {
1511                         is_valid = ast_ari_validate_void(
1512                                 response->message);
1513                 } else {
1514                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/hold\n", code);
1515                         is_valid = 0;
1516                 }
1517         }
1518
1519         if (!is_valid) {
1520                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/hold\n");
1521                 ast_ari_response_error(response, 500,
1522                         "Internal Server Error", "Response validation failed");
1523         }
1524 #endif /* AST_DEVMODE */
1525
1526 fin: __attribute__((unused))
1527         return;
1528 }
1529 /*!
1530  * \brief Parameter parsing callback for /channels/{channelId}/hold.
1531  * \param get_params GET parameters in the HTTP request.
1532  * \param path_vars Path variables extracted from the request.
1533  * \param headers HTTP headers.
1534  * \param[out] response Response to the HTTP request.
1535  */
1536 static void ast_ari_channels_unhold_cb(
1537         struct ast_tcptls_session_instance *ser,
1538         struct ast_variable *get_params, struct ast_variable *path_vars,
1539         struct ast_variable *headers, struct ast_ari_response *response)
1540 {
1541         struct ast_ari_channels_unhold_args args = {};
1542         struct ast_variable *i;
1543         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1544 #if defined(AST_DEVMODE)
1545         int is_valid;
1546         int code;
1547 #endif /* AST_DEVMODE */
1548
1549         for (i = path_vars; i; i = i->next) {
1550                 if (strcmp(i->name, "channelId") == 0) {
1551                         args.channel_id = (i->value);
1552                 } else
1553                 {}
1554         }
1555         ast_ari_channels_unhold(headers, &args, response);
1556 #if defined(AST_DEVMODE)
1557         code = response->response_code;
1558
1559         switch (code) {
1560         case 0: /* Implementation is still a stub, or the code wasn't set */
1561                 is_valid = response->message == NULL;
1562                 break;
1563         case 500: /* Internal Server Error */
1564         case 501: /* Not Implemented */
1565         case 404: /* Channel not found */
1566         case 409: /* Channel not in a Stasis application */
1567         case 412: /* Channel in invalid state */
1568                 is_valid = 1;
1569                 break;
1570         default:
1571                 if (200 <= code && code <= 299) {
1572                         is_valid = ast_ari_validate_void(
1573                                 response->message);
1574                 } else {
1575                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/hold\n", code);
1576                         is_valid = 0;
1577                 }
1578         }
1579
1580         if (!is_valid) {
1581                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/hold\n");
1582                 ast_ari_response_error(response, 500,
1583                         "Internal Server Error", "Response validation failed");
1584         }
1585 #endif /* AST_DEVMODE */
1586
1587 fin: __attribute__((unused))
1588         return;
1589 }
1590 int ast_ari_channels_start_moh_parse_body(
1591         struct ast_json *body,
1592         struct ast_ari_channels_start_moh_args *args)
1593 {
1594         struct ast_json *field;
1595         /* Parse query parameters out of it */
1596         field = ast_json_object_get(body, "mohClass");
1597         if (field) {
1598                 args->moh_class = ast_json_string_get(field);
1599         }
1600         return 0;
1601 }
1602
1603 /*!
1604  * \brief Parameter parsing callback for /channels/{channelId}/moh.
1605  * \param get_params GET parameters in the HTTP request.
1606  * \param path_vars Path variables extracted from the request.
1607  * \param headers HTTP headers.
1608  * \param[out] response Response to the HTTP request.
1609  */
1610 static void ast_ari_channels_start_moh_cb(
1611         struct ast_tcptls_session_instance *ser,
1612         struct ast_variable *get_params, struct ast_variable *path_vars,
1613         struct ast_variable *headers, struct ast_ari_response *response)
1614 {
1615         struct ast_ari_channels_start_moh_args args = {};
1616         struct ast_variable *i;
1617         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1618 #if defined(AST_DEVMODE)
1619         int is_valid;
1620         int code;
1621 #endif /* AST_DEVMODE */
1622
1623         for (i = get_params; i; i = i->next) {
1624                 if (strcmp(i->name, "mohClass") == 0) {
1625                         args.moh_class = (i->value);
1626                 } else
1627                 {}
1628         }
1629         for (i = path_vars; i; i = i->next) {
1630                 if (strcmp(i->name, "channelId") == 0) {
1631                         args.channel_id = (i->value);
1632                 } else
1633                 {}
1634         }
1635         /* Look for a JSON request entity */
1636         body = ast_http_get_json(ser, headers);
1637         if (!body) {
1638                 switch (errno) {
1639                 case EFBIG:
1640                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
1641                         goto fin;
1642                 case ENOMEM:
1643                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
1644                         goto fin;
1645                 case EIO:
1646                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
1647                         goto fin;
1648                 }
1649         }
1650         if (ast_ari_channels_start_moh_parse_body(body, &args)) {
1651                 ast_ari_response_alloc_failed(response);
1652                 goto fin;
1653         }
1654         ast_ari_channels_start_moh(headers, &args, response);
1655 #if defined(AST_DEVMODE)
1656         code = response->response_code;
1657
1658         switch (code) {
1659         case 0: /* Implementation is still a stub, or the code wasn't set */
1660                 is_valid = response->message == NULL;
1661                 break;
1662         case 500: /* Internal Server Error */
1663         case 501: /* Not Implemented */
1664         case 404: /* Channel not found */
1665         case 409: /* Channel not in a Stasis application */
1666         case 412: /* Channel in invalid state */
1667                 is_valid = 1;
1668                 break;
1669         default:
1670                 if (200 <= code && code <= 299) {
1671                         is_valid = ast_ari_validate_void(
1672                                 response->message);
1673                 } else {
1674                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/moh\n", code);
1675                         is_valid = 0;
1676                 }
1677         }
1678
1679         if (!is_valid) {
1680                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/moh\n");
1681                 ast_ari_response_error(response, 500,
1682                         "Internal Server Error", "Response validation failed");
1683         }
1684 #endif /* AST_DEVMODE */
1685
1686 fin: __attribute__((unused))
1687         return;
1688 }
1689 /*!
1690  * \brief Parameter parsing callback for /channels/{channelId}/moh.
1691  * \param get_params GET parameters in the HTTP request.
1692  * \param path_vars Path variables extracted from the request.
1693  * \param headers HTTP headers.
1694  * \param[out] response Response to the HTTP request.
1695  */
1696 static void ast_ari_channels_stop_moh_cb(
1697         struct ast_tcptls_session_instance *ser,
1698         struct ast_variable *get_params, struct ast_variable *path_vars,
1699         struct ast_variable *headers, struct ast_ari_response *response)
1700 {
1701         struct ast_ari_channels_stop_moh_args args = {};
1702         struct ast_variable *i;
1703         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1704 #if defined(AST_DEVMODE)
1705         int is_valid;
1706         int code;
1707 #endif /* AST_DEVMODE */
1708
1709         for (i = path_vars; i; i = i->next) {
1710                 if (strcmp(i->name, "channelId") == 0) {
1711                         args.channel_id = (i->value);
1712                 } else
1713                 {}
1714         }
1715         ast_ari_channels_stop_moh(headers, &args, response);
1716 #if defined(AST_DEVMODE)
1717         code = response->response_code;
1718
1719         switch (code) {
1720         case 0: /* Implementation is still a stub, or the code wasn't set */
1721                 is_valid = response->message == NULL;
1722                 break;
1723         case 500: /* Internal Server Error */
1724         case 501: /* Not Implemented */
1725         case 404: /* Channel not found */
1726         case 409: /* Channel not in a Stasis application */
1727         case 412: /* Channel in invalid state */
1728                 is_valid = 1;
1729                 break;
1730         default:
1731                 if (200 <= code && code <= 299) {
1732                         is_valid = ast_ari_validate_void(
1733                                 response->message);
1734                 } else {
1735                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/moh\n", code);
1736                         is_valid = 0;
1737                 }
1738         }
1739
1740         if (!is_valid) {
1741                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/moh\n");
1742                 ast_ari_response_error(response, 500,
1743                         "Internal Server Error", "Response validation failed");
1744         }
1745 #endif /* AST_DEVMODE */
1746
1747 fin: __attribute__((unused))
1748         return;
1749 }
1750 /*!
1751  * \brief Parameter parsing callback for /channels/{channelId}/silence.
1752  * \param get_params GET parameters in the HTTP request.
1753  * \param path_vars Path variables extracted from the request.
1754  * \param headers HTTP headers.
1755  * \param[out] response Response to the HTTP request.
1756  */
1757 static void ast_ari_channels_start_silence_cb(
1758         struct ast_tcptls_session_instance *ser,
1759         struct ast_variable *get_params, struct ast_variable *path_vars,
1760         struct ast_variable *headers, struct ast_ari_response *response)
1761 {
1762         struct ast_ari_channels_start_silence_args args = {};
1763         struct ast_variable *i;
1764         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1765 #if defined(AST_DEVMODE)
1766         int is_valid;
1767         int code;
1768 #endif /* AST_DEVMODE */
1769
1770         for (i = path_vars; i; i = i->next) {
1771                 if (strcmp(i->name, "channelId") == 0) {
1772                         args.channel_id = (i->value);
1773                 } else
1774                 {}
1775         }
1776         ast_ari_channels_start_silence(headers, &args, response);
1777 #if defined(AST_DEVMODE)
1778         code = response->response_code;
1779
1780         switch (code) {
1781         case 0: /* Implementation is still a stub, or the code wasn't set */
1782                 is_valid = response->message == NULL;
1783                 break;
1784         case 500: /* Internal Server Error */
1785         case 501: /* Not Implemented */
1786         case 404: /* Channel not found */
1787         case 409: /* Channel not in a Stasis application */
1788         case 412: /* Channel in invalid state */
1789                 is_valid = 1;
1790                 break;
1791         default:
1792                 if (200 <= code && code <= 299) {
1793                         is_valid = ast_ari_validate_void(
1794                                 response->message);
1795                 } else {
1796                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/silence\n", code);
1797                         is_valid = 0;
1798                 }
1799         }
1800
1801         if (!is_valid) {
1802                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/silence\n");
1803                 ast_ari_response_error(response, 500,
1804                         "Internal Server Error", "Response validation failed");
1805         }
1806 #endif /* AST_DEVMODE */
1807
1808 fin: __attribute__((unused))
1809         return;
1810 }
1811 /*!
1812  * \brief Parameter parsing callback for /channels/{channelId}/silence.
1813  * \param get_params GET parameters in the HTTP request.
1814  * \param path_vars Path variables extracted from the request.
1815  * \param headers HTTP headers.
1816  * \param[out] response Response to the HTTP request.
1817  */
1818 static void ast_ari_channels_stop_silence_cb(
1819         struct ast_tcptls_session_instance *ser,
1820         struct ast_variable *get_params, struct ast_variable *path_vars,
1821         struct ast_variable *headers, struct ast_ari_response *response)
1822 {
1823         struct ast_ari_channels_stop_silence_args args = {};
1824         struct ast_variable *i;
1825         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1826 #if defined(AST_DEVMODE)
1827         int is_valid;
1828         int code;
1829 #endif /* AST_DEVMODE */
1830
1831         for (i = path_vars; i; i = i->next) {
1832                 if (strcmp(i->name, "channelId") == 0) {
1833                         args.channel_id = (i->value);
1834                 } else
1835                 {}
1836         }
1837         ast_ari_channels_stop_silence(headers, &args, response);
1838 #if defined(AST_DEVMODE)
1839         code = response->response_code;
1840
1841         switch (code) {
1842         case 0: /* Implementation is still a stub, or the code wasn't set */
1843                 is_valid = response->message == NULL;
1844                 break;
1845         case 500: /* Internal Server Error */
1846         case 501: /* Not Implemented */
1847         case 404: /* Channel not found */
1848         case 409: /* Channel not in a Stasis application */
1849         case 412: /* Channel in invalid state */
1850                 is_valid = 1;
1851                 break;
1852         default:
1853                 if (200 <= code && code <= 299) {
1854                         is_valid = ast_ari_validate_void(
1855                                 response->message);
1856                 } else {
1857                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/silence\n", code);
1858                         is_valid = 0;
1859                 }
1860         }
1861
1862         if (!is_valid) {
1863                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/silence\n");
1864                 ast_ari_response_error(response, 500,
1865                         "Internal Server Error", "Response validation failed");
1866         }
1867 #endif /* AST_DEVMODE */
1868
1869 fin: __attribute__((unused))
1870         return;
1871 }
1872 int ast_ari_channels_play_parse_body(
1873         struct ast_json *body,
1874         struct ast_ari_channels_play_args *args)
1875 {
1876         struct ast_json *field;
1877         /* Parse query parameters out of it */
1878         field = ast_json_object_get(body, "media");
1879         if (field) {
1880                 /* If they were silly enough to both pass in a query param and a
1881                  * JSON body, free up the query value.
1882                  */
1883                 ast_free(args->media);
1884                 if (ast_json_typeof(field) == AST_JSON_ARRAY) {
1885                         /* Multiple param passed as array */
1886                         size_t i;
1887                         args->media_count = ast_json_array_size(field);
1888                         args->media = ast_malloc(sizeof(*args->media) * args->media_count);
1889
1890                         if (!args->media) {
1891                                 return -1;
1892                         }
1893
1894                         for (i = 0; i < args->media_count; ++i) {
1895                                 args->media[i] = ast_json_string_get(ast_json_array_get(field, i));
1896                         }
1897                 } else {
1898                         /* Multiple param passed as single value */
1899                         args->media_count = 1;
1900                         args->media = ast_malloc(sizeof(*args->media) * args->media_count);
1901                         if (!args->media) {
1902                                 return -1;
1903                         }
1904                         args->media[0] = ast_json_string_get(field);
1905                 }
1906         }
1907         field = ast_json_object_get(body, "lang");
1908         if (field) {
1909                 args->lang = ast_json_string_get(field);
1910         }
1911         field = ast_json_object_get(body, "offsetms");
1912         if (field) {
1913                 args->offsetms = ast_json_integer_get(field);
1914         }
1915         field = ast_json_object_get(body, "skipms");
1916         if (field) {
1917                 args->skipms = ast_json_integer_get(field);
1918         }
1919         field = ast_json_object_get(body, "playbackId");
1920         if (field) {
1921                 args->playback_id = ast_json_string_get(field);
1922         }
1923         return 0;
1924 }
1925
1926 /*!
1927  * \brief Parameter parsing callback for /channels/{channelId}/play.
1928  * \param get_params GET parameters in the HTTP request.
1929  * \param path_vars Path variables extracted from the request.
1930  * \param headers HTTP headers.
1931  * \param[out] response Response to the HTTP request.
1932  */
1933 static void ast_ari_channels_play_cb(
1934         struct ast_tcptls_session_instance *ser,
1935         struct ast_variable *get_params, struct ast_variable *path_vars,
1936         struct ast_variable *headers, struct ast_ari_response *response)
1937 {
1938         struct ast_ari_channels_play_args args = {};
1939         struct ast_variable *i;
1940         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1941 #if defined(AST_DEVMODE)
1942         int is_valid;
1943         int code;
1944 #endif /* AST_DEVMODE */
1945
1946         for (i = get_params; i; i = i->next) {
1947                 if (strcmp(i->name, "media") == 0) {
1948                         /* Parse comma separated list */
1949                         char *vals[MAX_VALS];
1950                         size_t j;
1951
1952                         args.media_parse = ast_strdup(i->value);
1953                         if (!args.media_parse) {
1954                                 ast_ari_response_alloc_failed(response);
1955                                 goto fin;
1956                         }
1957
1958                         if (strlen(args.media_parse) == 0) {
1959                                 /* ast_app_separate_args can't handle "" */
1960                                 args.media_count = 1;
1961                                 vals[0] = args.media_parse;
1962                         } else {
1963                                 args.media_count = ast_app_separate_args(
1964                                         args.media_parse, ',', vals,
1965                                         ARRAY_LEN(vals));
1966                         }
1967
1968                         if (args.media_count == 0) {
1969                                 ast_ari_response_alloc_failed(response);
1970                                 goto fin;
1971                         }
1972
1973                         if (args.media_count >= MAX_VALS) {
1974                                 ast_ari_response_error(response, 400,
1975                                         "Bad Request",
1976                                         "Too many values for media");
1977                                 goto fin;
1978                         }
1979
1980                         args.media = ast_malloc(sizeof(*args.media) * args.media_count);
1981                         if (!args.media) {
1982                                 ast_ari_response_alloc_failed(response);
1983                                 goto fin;
1984                         }
1985
1986                         for (j = 0; j < args.media_count; ++j) {
1987                                 args.media[j] = (vals[j]);
1988                         }
1989                 } else
1990                 if (strcmp(i->name, "lang") == 0) {
1991                         args.lang = (i->value);
1992                 } else
1993                 if (strcmp(i->name, "offsetms") == 0) {
1994                         args.offsetms = atoi(i->value);
1995                 } else
1996                 if (strcmp(i->name, "skipms") == 0) {
1997                         args.skipms = atoi(i->value);
1998                 } else
1999                 if (strcmp(i->name, "playbackId") == 0) {
2000                         args.playback_id = (i->value);
2001                 } else
2002                 {}
2003         }
2004         for (i = path_vars; i; i = i->next) {
2005                 if (strcmp(i->name, "channelId") == 0) {
2006                         args.channel_id = (i->value);
2007                 } else
2008                 {}
2009         }
2010         /* Look for a JSON request entity */
2011         body = ast_http_get_json(ser, headers);
2012         if (!body) {
2013                 switch (errno) {
2014                 case EFBIG:
2015                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
2016                         goto fin;
2017                 case ENOMEM:
2018                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
2019                         goto fin;
2020                 case EIO:
2021                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
2022                         goto fin;
2023                 }
2024         }
2025         if (ast_ari_channels_play_parse_body(body, &args)) {
2026                 ast_ari_response_alloc_failed(response);
2027                 goto fin;
2028         }
2029         ast_ari_channels_play(headers, &args, response);
2030 #if defined(AST_DEVMODE)
2031         code = response->response_code;
2032
2033         switch (code) {
2034         case 0: /* Implementation is still a stub, or the code wasn't set */
2035                 is_valid = response->message == NULL;
2036                 break;
2037         case 500: /* Internal Server Error */
2038         case 501: /* Not Implemented */
2039         case 404: /* Channel not found */
2040         case 409: /* Channel not in a Stasis application */
2041         case 412: /* Channel in invalid state */
2042                 is_valid = 1;
2043                 break;
2044         default:
2045                 if (200 <= code && code <= 299) {
2046                         is_valid = ast_ari_validate_playback(
2047                                 response->message);
2048                 } else {
2049                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/play\n", code);
2050                         is_valid = 0;
2051                 }
2052         }
2053
2054         if (!is_valid) {
2055                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/play\n");
2056                 ast_ari_response_error(response, 500,
2057                         "Internal Server Error", "Response validation failed");
2058         }
2059 #endif /* AST_DEVMODE */
2060
2061 fin: __attribute__((unused))
2062         ast_free(args.media_parse);
2063         ast_free(args.media);
2064         return;
2065 }
2066 int ast_ari_channels_play_with_id_parse_body(
2067         struct ast_json *body,
2068         struct ast_ari_channels_play_with_id_args *args)
2069 {
2070         struct ast_json *field;
2071         /* Parse query parameters out of it */
2072         field = ast_json_object_get(body, "media");
2073         if (field) {
2074                 /* If they were silly enough to both pass in a query param and a
2075                  * JSON body, free up the query value.
2076                  */
2077                 ast_free(args->media);
2078                 if (ast_json_typeof(field) == AST_JSON_ARRAY) {
2079                         /* Multiple param passed as array */
2080                         size_t i;
2081                         args->media_count = ast_json_array_size(field);
2082                         args->media = ast_malloc(sizeof(*args->media) * args->media_count);
2083
2084                         if (!args->media) {
2085                                 return -1;
2086                         }
2087
2088                         for (i = 0; i < args->media_count; ++i) {
2089                                 args->media[i] = ast_json_string_get(ast_json_array_get(field, i));
2090                         }
2091                 } else {
2092                         /* Multiple param passed as single value */
2093                         args->media_count = 1;
2094                         args->media = ast_malloc(sizeof(*args->media) * args->media_count);
2095                         if (!args->media) {
2096                                 return -1;
2097                         }
2098                         args->media[0] = ast_json_string_get(field);
2099                 }
2100         }
2101         field = ast_json_object_get(body, "lang");
2102         if (field) {
2103                 args->lang = ast_json_string_get(field);
2104         }
2105         field = ast_json_object_get(body, "offsetms");
2106         if (field) {
2107                 args->offsetms = ast_json_integer_get(field);
2108         }
2109         field = ast_json_object_get(body, "skipms");
2110         if (field) {
2111                 args->skipms = ast_json_integer_get(field);
2112         }
2113         return 0;
2114 }
2115
2116 /*!
2117  * \brief Parameter parsing callback for /channels/{channelId}/play/{playbackId}.
2118  * \param get_params GET parameters in the HTTP request.
2119  * \param path_vars Path variables extracted from the request.
2120  * \param headers HTTP headers.
2121  * \param[out] response Response to the HTTP request.
2122  */
2123 static void ast_ari_channels_play_with_id_cb(
2124         struct ast_tcptls_session_instance *ser,
2125         struct ast_variable *get_params, struct ast_variable *path_vars,
2126         struct ast_variable *headers, struct ast_ari_response *response)
2127 {
2128         struct ast_ari_channels_play_with_id_args args = {};
2129         struct ast_variable *i;
2130         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
2131 #if defined(AST_DEVMODE)
2132         int is_valid;
2133         int code;
2134 #endif /* AST_DEVMODE */
2135
2136         for (i = get_params; i; i = i->next) {
2137                 if (strcmp(i->name, "media") == 0) {
2138                         /* Parse comma separated list */
2139                         char *vals[MAX_VALS];
2140                         size_t j;
2141
2142                         args.media_parse = ast_strdup(i->value);
2143                         if (!args.media_parse) {
2144                                 ast_ari_response_alloc_failed(response);
2145                                 goto fin;
2146                         }
2147
2148                         if (strlen(args.media_parse) == 0) {
2149                                 /* ast_app_separate_args can't handle "" */
2150                                 args.media_count = 1;
2151                                 vals[0] = args.media_parse;
2152                         } else {
2153                                 args.media_count = ast_app_separate_args(
2154                                         args.media_parse, ',', vals,
2155                                         ARRAY_LEN(vals));
2156                         }
2157
2158                         if (args.media_count == 0) {
2159                                 ast_ari_response_alloc_failed(response);
2160                                 goto fin;
2161                         }
2162
2163                         if (args.media_count >= MAX_VALS) {
2164                                 ast_ari_response_error(response, 400,
2165                                         "Bad Request",
2166                                         "Too many values for media");
2167                                 goto fin;
2168                         }
2169
2170                         args.media = ast_malloc(sizeof(*args.media) * args.media_count);
2171                         if (!args.media) {
2172                                 ast_ari_response_alloc_failed(response);
2173                                 goto fin;
2174                         }
2175
2176                         for (j = 0; j < args.media_count; ++j) {
2177                                 args.media[j] = (vals[j]);
2178                         }
2179                 } else
2180                 if (strcmp(i->name, "lang") == 0) {
2181                         args.lang = (i->value);
2182                 } else
2183                 if (strcmp(i->name, "offsetms") == 0) {
2184                         args.offsetms = atoi(i->value);
2185                 } else
2186                 if (strcmp(i->name, "skipms") == 0) {
2187                         args.skipms = atoi(i->value);
2188                 } else
2189                 {}
2190         }
2191         for (i = path_vars; i; i = i->next) {
2192                 if (strcmp(i->name, "channelId") == 0) {
2193                         args.channel_id = (i->value);
2194                 } else
2195                 if (strcmp(i->name, "playbackId") == 0) {
2196                         args.playback_id = (i->value);
2197                 } else
2198                 {}
2199         }
2200         /* Look for a JSON request entity */
2201         body = ast_http_get_json(ser, headers);
2202         if (!body) {
2203                 switch (errno) {
2204                 case EFBIG:
2205                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
2206                         goto fin;
2207                 case ENOMEM:
2208                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
2209                         goto fin;
2210                 case EIO:
2211                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
2212                         goto fin;
2213                 }
2214         }
2215         if (ast_ari_channels_play_with_id_parse_body(body, &args)) {
2216                 ast_ari_response_alloc_failed(response);
2217                 goto fin;
2218         }
2219         ast_ari_channels_play_with_id(headers, &args, response);
2220 #if defined(AST_DEVMODE)
2221         code = response->response_code;
2222
2223         switch (code) {
2224         case 0: /* Implementation is still a stub, or the code wasn't set */
2225                 is_valid = response->message == NULL;
2226                 break;
2227         case 500: /* Internal Server Error */
2228         case 501: /* Not Implemented */
2229         case 404: /* Channel not found */
2230         case 409: /* Channel not in a Stasis application */
2231         case 412: /* Channel in invalid state */
2232                 is_valid = 1;
2233                 break;
2234         default:
2235                 if (200 <= code && code <= 299) {
2236                         is_valid = ast_ari_validate_playback(
2237                                 response->message);
2238                 } else {
2239                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/play/{playbackId}\n", code);
2240                         is_valid = 0;
2241                 }
2242         }
2243
2244         if (!is_valid) {
2245                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/play/{playbackId}\n");
2246                 ast_ari_response_error(response, 500,
2247                         "Internal Server Error", "Response validation failed");
2248         }
2249 #endif /* AST_DEVMODE */
2250
2251 fin: __attribute__((unused))
2252         ast_free(args.media_parse);
2253         ast_free(args.media);
2254         return;
2255 }
2256 int ast_ari_channels_record_parse_body(
2257         struct ast_json *body,
2258         struct ast_ari_channels_record_args *args)
2259 {
2260         struct ast_json *field;
2261         /* Parse query parameters out of it */
2262         field = ast_json_object_get(body, "name");
2263         if (field) {
2264                 args->name = ast_json_string_get(field);
2265         }
2266         field = ast_json_object_get(body, "format");
2267         if (field) {
2268                 args->format = ast_json_string_get(field);
2269         }
2270         field = ast_json_object_get(body, "maxDurationSeconds");
2271         if (field) {
2272                 args->max_duration_seconds = ast_json_integer_get(field);
2273         }
2274         field = ast_json_object_get(body, "maxSilenceSeconds");
2275         if (field) {
2276                 args->max_silence_seconds = ast_json_integer_get(field);
2277         }
2278         field = ast_json_object_get(body, "ifExists");
2279         if (field) {
2280                 args->if_exists = ast_json_string_get(field);
2281         }
2282         field = ast_json_object_get(body, "beep");
2283         if (field) {
2284                 args->beep = ast_json_is_true(field);
2285         }
2286         field = ast_json_object_get(body, "terminateOn");
2287         if (field) {
2288                 args->terminate_on = ast_json_string_get(field);
2289         }
2290         return 0;
2291 }
2292
2293 /*!
2294  * \brief Parameter parsing callback for /channels/{channelId}/record.
2295  * \param get_params GET parameters in the HTTP request.
2296  * \param path_vars Path variables extracted from the request.
2297  * \param headers HTTP headers.
2298  * \param[out] response Response to the HTTP request.
2299  */
2300 static void ast_ari_channels_record_cb(
2301         struct ast_tcptls_session_instance *ser,
2302         struct ast_variable *get_params, struct ast_variable *path_vars,
2303         struct ast_variable *headers, struct ast_ari_response *response)
2304 {
2305         struct ast_ari_channels_record_args args = {};
2306         struct ast_variable *i;
2307         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
2308 #if defined(AST_DEVMODE)
2309         int is_valid;
2310         int code;
2311 #endif /* AST_DEVMODE */
2312
2313         for (i = get_params; i; i = i->next) {
2314                 if (strcmp(i->name, "name") == 0) {
2315                         args.name = (i->value);
2316                 } else
2317                 if (strcmp(i->name, "format") == 0) {
2318                         args.format = (i->value);
2319                 } else
2320                 if (strcmp(i->name, "maxDurationSeconds") == 0) {
2321                         args.max_duration_seconds = atoi(i->value);
2322                 } else
2323                 if (strcmp(i->name, "maxSilenceSeconds") == 0) {
2324                         args.max_silence_seconds = atoi(i->value);
2325                 } else
2326                 if (strcmp(i->name, "ifExists") == 0) {
2327                         args.if_exists = (i->value);
2328                 } else
2329                 if (strcmp(i->name, "beep") == 0) {
2330                         args.beep = ast_true(i->value);
2331                 } else
2332                 if (strcmp(i->name, "terminateOn") == 0) {
2333                         args.terminate_on = (i->value);
2334                 } else
2335                 {}
2336         }
2337         for (i = path_vars; i; i = i->next) {
2338                 if (strcmp(i->name, "channelId") == 0) {
2339                         args.channel_id = (i->value);
2340                 } else
2341                 {}
2342         }
2343         /* Look for a JSON request entity */
2344         body = ast_http_get_json(ser, headers);
2345         if (!body) {
2346                 switch (errno) {
2347                 case EFBIG:
2348                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
2349                         goto fin;
2350                 case ENOMEM:
2351                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
2352                         goto fin;
2353                 case EIO:
2354                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
2355                         goto fin;
2356                 }
2357         }
2358         if (ast_ari_channels_record_parse_body(body, &args)) {
2359                 ast_ari_response_alloc_failed(response);
2360                 goto fin;
2361         }
2362         ast_ari_channels_record(headers, &args, response);
2363 #if defined(AST_DEVMODE)
2364         code = response->response_code;
2365
2366         switch (code) {
2367         case 0: /* Implementation is still a stub, or the code wasn't set */
2368                 is_valid = response->message == NULL;
2369                 break;
2370         case 500: /* Internal Server Error */
2371         case 501: /* Not Implemented */
2372         case 400: /* Invalid parameters */
2373         case 404: /* Channel not found */
2374         case 409: /* Channel is not in a Stasis application; the channel is currently bridged with other hcannels; A recording with the same name already exists on the system and can not be overwritten because it is in progress or ifExists=fail */
2375         case 422: /* The format specified is unknown on this system */
2376                 is_valid = 1;
2377                 break;
2378         default:
2379                 if (200 <= code && code <= 299) {
2380                         is_valid = ast_ari_validate_live_recording(
2381                                 response->message);
2382                 } else {
2383                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/record\n", code);
2384                         is_valid = 0;
2385                 }
2386         }
2387
2388         if (!is_valid) {
2389                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/record\n");
2390                 ast_ari_response_error(response, 500,
2391                         "Internal Server Error", "Response validation failed");
2392         }
2393 #endif /* AST_DEVMODE */
2394
2395 fin: __attribute__((unused))
2396         return;
2397 }
2398 int ast_ari_channels_get_channel_var_parse_body(
2399         struct ast_json *body,
2400         struct ast_ari_channels_get_channel_var_args *args)
2401 {
2402         struct ast_json *field;
2403         /* Parse query parameters out of it */
2404         field = ast_json_object_get(body, "variable");
2405         if (field) {
2406                 args->variable = ast_json_string_get(field);
2407         }
2408         return 0;
2409 }
2410
2411 /*!
2412  * \brief Parameter parsing callback for /channels/{channelId}/variable.
2413  * \param get_params GET parameters in the HTTP request.
2414  * \param path_vars Path variables extracted from the request.
2415  * \param headers HTTP headers.
2416  * \param[out] response Response to the HTTP request.
2417  */
2418 static void ast_ari_channels_get_channel_var_cb(
2419         struct ast_tcptls_session_instance *ser,
2420         struct ast_variable *get_params, struct ast_variable *path_vars,
2421         struct ast_variable *headers, struct ast_ari_response *response)
2422 {
2423         struct ast_ari_channels_get_channel_var_args args = {};
2424         struct ast_variable *i;
2425         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
2426 #if defined(AST_DEVMODE)
2427         int is_valid;
2428         int code;
2429 #endif /* AST_DEVMODE */
2430
2431         for (i = get_params; i; i = i->next) {
2432                 if (strcmp(i->name, "variable") == 0) {
2433                         args.variable = (i->value);
2434                 } else
2435                 {}
2436         }
2437         for (i = path_vars; i; i = i->next) {
2438                 if (strcmp(i->name, "channelId") == 0) {
2439                         args.channel_id = (i->value);
2440                 } else
2441                 {}
2442         }
2443         /* Look for a JSON request entity */
2444         body = ast_http_get_json(ser, headers);
2445         if (!body) {
2446                 switch (errno) {
2447                 case EFBIG:
2448                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
2449                         goto fin;
2450                 case ENOMEM:
2451                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
2452                         goto fin;
2453                 case EIO:
2454                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
2455                         goto fin;
2456                 }
2457         }
2458         if (ast_ari_channels_get_channel_var_parse_body(body, &args)) {
2459                 ast_ari_response_alloc_failed(response);
2460                 goto fin;
2461         }
2462         ast_ari_channels_get_channel_var(headers, &args, response);
2463 #if defined(AST_DEVMODE)
2464         code = response->response_code;
2465
2466         switch (code) {
2467         case 0: /* Implementation is still a stub, or the code wasn't set */
2468                 is_valid = response->message == NULL;
2469                 break;
2470         case 500: /* Internal Server Error */
2471         case 501: /* Not Implemented */
2472         case 400: /* Missing variable parameter. */
2473         case 404: /* Channel or variable not found */
2474         case 409: /* Channel not in a Stasis application */
2475                 is_valid = 1;
2476                 break;
2477         default:
2478                 if (200 <= code && code <= 299) {
2479                         is_valid = ast_ari_validate_variable(
2480                                 response->message);
2481                 } else {
2482                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/variable\n", code);
2483                         is_valid = 0;
2484                 }
2485         }
2486
2487         if (!is_valid) {
2488                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/variable\n");
2489                 ast_ari_response_error(response, 500,
2490                         "Internal Server Error", "Response validation failed");
2491         }
2492 #endif /* AST_DEVMODE */
2493
2494 fin: __attribute__((unused))
2495         return;
2496 }
2497 int ast_ari_channels_set_channel_var_parse_body(
2498         struct ast_json *body,
2499         struct ast_ari_channels_set_channel_var_args *args)
2500 {
2501         struct ast_json *field;
2502         /* Parse query parameters out of it */
2503         field = ast_json_object_get(body, "variable");
2504         if (field) {
2505                 args->variable = ast_json_string_get(field);
2506         }
2507         field = ast_json_object_get(body, "value");
2508         if (field) {
2509                 args->value = ast_json_string_get(field);
2510         }
2511         return 0;
2512 }
2513
2514 /*!
2515  * \brief Parameter parsing callback for /channels/{channelId}/variable.
2516  * \param get_params GET parameters in the HTTP request.
2517  * \param path_vars Path variables extracted from the request.
2518  * \param headers HTTP headers.
2519  * \param[out] response Response to the HTTP request.
2520  */
2521 static void ast_ari_channels_set_channel_var_cb(
2522         struct ast_tcptls_session_instance *ser,
2523         struct ast_variable *get_params, struct ast_variable *path_vars,
2524         struct ast_variable *headers, struct ast_ari_response *response)
2525 {
2526         struct ast_ari_channels_set_channel_var_args args = {};
2527         struct ast_variable *i;
2528         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
2529 #if defined(AST_DEVMODE)
2530         int is_valid;
2531         int code;
2532 #endif /* AST_DEVMODE */
2533
2534         for (i = get_params; i; i = i->next) {
2535                 if (strcmp(i->name, "variable") == 0) {
2536                         args.variable = (i->value);
2537                 } else
2538                 if (strcmp(i->name, "value") == 0) {
2539                         args.value = (i->value);
2540                 } else
2541                 {}
2542         }
2543         for (i = path_vars; i; i = i->next) {
2544                 if (strcmp(i->name, "channelId") == 0) {
2545                         args.channel_id = (i->value);
2546                 } else
2547                 {}
2548         }
2549         /* Look for a JSON request entity */
2550         body = ast_http_get_json(ser, headers);
2551         if (!body) {
2552                 switch (errno) {
2553                 case EFBIG:
2554                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
2555                         goto fin;
2556                 case ENOMEM:
2557                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
2558                         goto fin;
2559                 case EIO:
2560                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
2561                         goto fin;
2562                 }
2563         }
2564         if (ast_ari_channels_set_channel_var_parse_body(body, &args)) {
2565                 ast_ari_response_alloc_failed(response);
2566                 goto fin;
2567         }
2568         ast_ari_channels_set_channel_var(headers, &args, response);
2569 #if defined(AST_DEVMODE)
2570         code = response->response_code;
2571
2572         switch (code) {
2573         case 0: /* Implementation is still a stub, or the code wasn't set */
2574                 is_valid = response->message == NULL;
2575                 break;
2576         case 500: /* Internal Server Error */
2577         case 501: /* Not Implemented */
2578         case 400: /* Missing variable parameter. */
2579         case 404: /* Channel not found */
2580         case 409: /* Channel not in a Stasis application */
2581                 is_valid = 1;
2582                 break;
2583         default:
2584                 if (200 <= code && code <= 299) {
2585                         is_valid = ast_ari_validate_void(
2586                                 response->message);
2587                 } else {
2588                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/variable\n", code);
2589                         is_valid = 0;
2590                 }
2591         }
2592
2593         if (!is_valid) {
2594                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/variable\n");
2595                 ast_ari_response_error(response, 500,
2596                         "Internal Server Error", "Response validation failed");
2597         }
2598 #endif /* AST_DEVMODE */
2599
2600 fin: __attribute__((unused))
2601         return;
2602 }
2603 int ast_ari_channels_snoop_channel_parse_body(
2604         struct ast_json *body,
2605         struct ast_ari_channels_snoop_channel_args *args)
2606 {
2607         struct ast_json *field;
2608         /* Parse query parameters out of it */
2609         field = ast_json_object_get(body, "spy");
2610         if (field) {
2611                 args->spy = ast_json_string_get(field);
2612         }
2613         field = ast_json_object_get(body, "whisper");
2614         if (field) {
2615                 args->whisper = ast_json_string_get(field);
2616         }
2617         field = ast_json_object_get(body, "app");
2618         if (field) {
2619                 args->app = ast_json_string_get(field);
2620         }
2621         field = ast_json_object_get(body, "appArgs");
2622         if (field) {
2623                 args->app_args = ast_json_string_get(field);
2624         }
2625         field = ast_json_object_get(body, "snoopId");
2626         if (field) {
2627                 args->snoop_id = ast_json_string_get(field);
2628         }
2629         return 0;
2630 }
2631
2632 /*!
2633  * \brief Parameter parsing callback for /channels/{channelId}/snoop.
2634  * \param get_params GET parameters in the HTTP request.
2635  * \param path_vars Path variables extracted from the request.
2636  * \param headers HTTP headers.
2637  * \param[out] response Response to the HTTP request.
2638  */
2639 static void ast_ari_channels_snoop_channel_cb(
2640         struct ast_tcptls_session_instance *ser,
2641         struct ast_variable *get_params, struct ast_variable *path_vars,
2642         struct ast_variable *headers, struct ast_ari_response *response)
2643 {
2644         struct ast_ari_channels_snoop_channel_args args = {};
2645         struct ast_variable *i;
2646         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
2647 #if defined(AST_DEVMODE)
2648         int is_valid;
2649         int code;
2650 #endif /* AST_DEVMODE */
2651
2652         for (i = get_params; i; i = i->next) {
2653                 if (strcmp(i->name, "spy") == 0) {
2654                         args.spy = (i->value);
2655                 } else
2656                 if (strcmp(i->name, "whisper") == 0) {
2657                         args.whisper = (i->value);
2658                 } else
2659                 if (strcmp(i->name, "app") == 0) {
2660                         args.app = (i->value);
2661                 } else
2662                 if (strcmp(i->name, "appArgs") == 0) {
2663                         args.app_args = (i->value);
2664                 } else
2665                 if (strcmp(i->name, "snoopId") == 0) {
2666                         args.snoop_id = (i->value);
2667                 } else
2668                 {}
2669         }
2670         for (i = path_vars; i; i = i->next) {
2671                 if (strcmp(i->name, "channelId") == 0) {
2672                         args.channel_id = (i->value);
2673                 } else
2674                 {}
2675         }
2676         /* Look for a JSON request entity */
2677         body = ast_http_get_json(ser, headers);
2678         if (!body) {
2679                 switch (errno) {
2680                 case EFBIG:
2681                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
2682                         goto fin;
2683                 case ENOMEM:
2684                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
2685                         goto fin;
2686                 case EIO:
2687                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
2688                         goto fin;
2689                 }
2690         }
2691         if (ast_ari_channels_snoop_channel_parse_body(body, &args)) {
2692                 ast_ari_response_alloc_failed(response);
2693                 goto fin;
2694         }
2695         ast_ari_channels_snoop_channel(headers, &args, response);
2696 #if defined(AST_DEVMODE)
2697         code = response->response_code;
2698
2699         switch (code) {
2700         case 0: /* Implementation is still a stub, or the code wasn't set */
2701                 is_valid = response->message == NULL;
2702                 break;
2703         case 500: /* Internal Server Error */
2704         case 501: /* Not Implemented */
2705         case 400: /* Invalid parameters */
2706         case 404: /* Channel not found */
2707                 is_valid = 1;
2708                 break;
2709         default:
2710                 if (200 <= code && code <= 299) {
2711                         is_valid = ast_ari_validate_channel(
2712                                 response->message);
2713                 } else {
2714                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/snoop\n", code);
2715                         is_valid = 0;
2716                 }
2717         }
2718
2719         if (!is_valid) {
2720                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/snoop\n");
2721                 ast_ari_response_error(response, 500,
2722                         "Internal Server Error", "Response validation failed");
2723         }
2724 #endif /* AST_DEVMODE */
2725
2726 fin: __attribute__((unused))
2727         return;
2728 }
2729 int ast_ari_channels_snoop_channel_with_id_parse_body(
2730         struct ast_json *body,
2731         struct ast_ari_channels_snoop_channel_with_id_args *args)
2732 {
2733         struct ast_json *field;
2734         /* Parse query parameters out of it */
2735         field = ast_json_object_get(body, "spy");
2736         if (field) {
2737                 args->spy = ast_json_string_get(field);
2738         }
2739         field = ast_json_object_get(body, "whisper");
2740         if (field) {
2741                 args->whisper = ast_json_string_get(field);
2742         }
2743         field = ast_json_object_get(body, "app");
2744         if (field) {
2745                 args->app = ast_json_string_get(field);
2746         }
2747         field = ast_json_object_get(body, "appArgs");
2748         if (field) {
2749                 args->app_args = ast_json_string_get(field);
2750         }
2751         return 0;
2752 }
2753
2754 /*!
2755  * \brief Parameter parsing callback for /channels/{channelId}/snoop/{snoopId}.
2756  * \param get_params GET parameters in the HTTP request.
2757  * \param path_vars Path variables extracted from the request.
2758  * \param headers HTTP headers.
2759  * \param[out] response Response to the HTTP request.
2760  */
2761 static void ast_ari_channels_snoop_channel_with_id_cb(
2762         struct ast_tcptls_session_instance *ser,
2763         struct ast_variable *get_params, struct ast_variable *path_vars,
2764         struct ast_variable *headers, struct ast_ari_response *response)
2765 {
2766         struct ast_ari_channels_snoop_channel_with_id_args args = {};
2767         struct ast_variable *i;
2768         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
2769 #if defined(AST_DEVMODE)
2770         int is_valid;
2771         int code;
2772 #endif /* AST_DEVMODE */
2773
2774         for (i = get_params; i; i = i->next) {
2775                 if (strcmp(i->name, "spy") == 0) {
2776                         args.spy = (i->value);
2777                 } else
2778                 if (strcmp(i->name, "whisper") == 0) {
2779                         args.whisper = (i->value);
2780                 } else
2781                 if (strcmp(i->name, "app") == 0) {
2782                         args.app = (i->value);
2783                 } else
2784                 if (strcmp(i->name, "appArgs") == 0) {
2785                         args.app_args = (i->value);
2786                 } else
2787                 {}
2788         }
2789         for (i = path_vars; i; i = i->next) {
2790                 if (strcmp(i->name, "channelId") == 0) {
2791                         args.channel_id = (i->value);
2792                 } else
2793                 if (strcmp(i->name, "snoopId") == 0) {
2794                         args.snoop_id = (i->value);
2795                 } else
2796                 {}
2797         }
2798         /* Look for a JSON request entity */
2799         body = ast_http_get_json(ser, headers);
2800         if (!body) {
2801                 switch (errno) {
2802                 case EFBIG:
2803                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
2804                         goto fin;
2805                 case ENOMEM:
2806                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
2807                         goto fin;
2808                 case EIO:
2809                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
2810                         goto fin;
2811                 }
2812         }
2813         if (ast_ari_channels_snoop_channel_with_id_parse_body(body, &args)) {
2814                 ast_ari_response_alloc_failed(response);
2815                 goto fin;
2816         }
2817         ast_ari_channels_snoop_channel_with_id(headers, &args, response);
2818 #if defined(AST_DEVMODE)
2819         code = response->response_code;
2820
2821         switch (code) {
2822         case 0: /* Implementation is still a stub, or the code wasn't set */
2823                 is_valid = response->message == NULL;
2824                 break;
2825         case 500: /* Internal Server Error */
2826         case 501: /* Not Implemented */
2827         case 400: /* Invalid parameters */
2828         case 404: /* Channel not found */
2829                 is_valid = 1;
2830                 break;
2831         default:
2832                 if (200 <= code && code <= 299) {
2833                         is_valid = ast_ari_validate_channel(
2834                                 response->message);
2835                 } else {
2836                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/snoop/{snoopId}\n", code);
2837                         is_valid = 0;
2838                 }
2839         }
2840
2841         if (!is_valid) {
2842                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/snoop/{snoopId}\n");
2843                 ast_ari_response_error(response, 500,
2844                         "Internal Server Error", "Response validation failed");
2845         }
2846 #endif /* AST_DEVMODE */
2847
2848 fin: __attribute__((unused))
2849         return;
2850 }
2851 int ast_ari_channels_dial_parse_body(
2852         struct ast_json *body,
2853         struct ast_ari_channels_dial_args *args)
2854 {
2855         struct ast_json *field;
2856         /* Parse query parameters out of it */
2857         field = ast_json_object_get(body, "caller");
2858         if (field) {
2859                 args->caller = ast_json_string_get(field);
2860         }
2861         field = ast_json_object_get(body, "timeout");
2862         if (field) {
2863                 args->timeout = ast_json_integer_get(field);
2864         }
2865         return 0;
2866 }
2867
2868 /*!
2869  * \brief Parameter parsing callback for /channels/{channelId}/dial.
2870  * \param get_params GET parameters in the HTTP request.
2871  * \param path_vars Path variables extracted from the request.
2872  * \param headers HTTP headers.
2873  * \param[out] response Response to the HTTP request.
2874  */
2875 static void ast_ari_channels_dial_cb(
2876         struct ast_tcptls_session_instance *ser,
2877         struct ast_variable *get_params, struct ast_variable *path_vars,
2878         struct ast_variable *headers, struct ast_ari_response *response)
2879 {
2880         struct ast_ari_channels_dial_args args = {};
2881         struct ast_variable *i;
2882         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
2883 #if defined(AST_DEVMODE)
2884         int is_valid;
2885         int code;
2886 #endif /* AST_DEVMODE */
2887
2888         for (i = get_params; i; i = i->next) {
2889                 if (strcmp(i->name, "caller") == 0) {
2890                         args.caller = (i->value);
2891                 } else
2892                 if (strcmp(i->name, "timeout") == 0) {
2893                         args.timeout = atoi(i->value);
2894                 } else
2895                 {}
2896         }
2897         for (i = path_vars; i; i = i->next) {
2898                 if (strcmp(i->name, "channelId") == 0) {
2899                         args.channel_id = (i->value);
2900                 } else
2901                 {}
2902         }
2903         /* Look for a JSON request entity */
2904         body = ast_http_get_json(ser, headers);
2905         if (!body) {
2906                 switch (errno) {
2907                 case EFBIG:
2908                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
2909                         goto fin;
2910                 case ENOMEM:
2911                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
2912                         goto fin;
2913                 case EIO:
2914                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
2915                         goto fin;
2916                 }
2917         }
2918         if (ast_ari_channels_dial_parse_body(body, &args)) {
2919                 ast_ari_response_alloc_failed(response);
2920                 goto fin;
2921         }
2922         ast_ari_channels_dial(headers, &args, response);
2923 #if defined(AST_DEVMODE)
2924         code = response->response_code;
2925
2926         switch (code) {
2927         case 0: /* Implementation is still a stub, or the code wasn't set */
2928                 is_valid = response->message == NULL;
2929                 break;
2930         case 500: /* Internal Server Error */
2931         case 501: /* Not Implemented */
2932         case 404: /* Channel cannot be found. */
2933         case 409: /* Channel cannot be dialed. */
2934                 is_valid = 1;
2935                 break;
2936         default:
2937                 if (200 <= code && code <= 299) {
2938                         is_valid = ast_ari_validate_void(
2939                                 response->message);
2940                 } else {
2941                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/dial\n", code);
2942                         is_valid = 0;
2943                 }
2944         }
2945
2946         if (!is_valid) {
2947                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/dial\n");
2948                 ast_ari_response_error(response, 500,
2949                         "Internal Server Error", "Response validation failed");
2950         }
2951 #endif /* AST_DEVMODE */
2952
2953 fin: __attribute__((unused))
2954         return;
2955 }
2956
2957 /*! \brief REST handler for /api-docs/channels.{format} */
2958 static struct stasis_rest_handlers channels_create = {
2959         .path_segment = "create",
2960         .callbacks = {
2961                 [AST_HTTP_POST] = ast_ari_channels_create_cb,
2962         },
2963         .num_children = 0,
2964         .children = {  }
2965 };
2966 /*! \brief REST handler for /api-docs/channels.{format} */
2967 static struct stasis_rest_handlers channels_channelId_continue = {
2968         .path_segment = "continue",
2969         .callbacks = {
2970                 [AST_HTTP_POST] = ast_ari_channels_continue_in_dialplan_cb,
2971         },
2972         .num_children = 0,
2973         .children = {  }
2974 };
2975 /*! \brief REST handler for /api-docs/channels.{format} */
2976 static struct stasis_rest_handlers channels_channelId_redirect = {
2977         .path_segment = "redirect",
2978         .callbacks = {
2979                 [AST_HTTP_POST] = ast_ari_channels_redirect_cb,
2980         },
2981         .num_children = 0,
2982         .children = {  }
2983 };
2984 /*! \brief REST handler for /api-docs/channels.{format} */
2985 static struct stasis_rest_handlers channels_channelId_answer = {
2986         .path_segment = "answer",
2987         .callbacks = {
2988                 [AST_HTTP_POST] = ast_ari_channels_answer_cb,
2989         },
2990         .num_children = 0,
2991         .children = {  }
2992 };
2993 /*! \brief REST handler for /api-docs/channels.{format} */
2994 static struct stasis_rest_handlers channels_channelId_ring = {
2995         .path_segment = "ring",
2996         .callbacks = {
2997                 [AST_HTTP_POST] = ast_ari_channels_ring_cb,
2998                 [AST_HTTP_DELETE] = ast_ari_channels_ring_stop_cb,
2999         },
3000         .num_children = 0,
3001         .children = {  }
3002 };
3003 /*! \brief REST handler for /api-docs/channels.{format} */
3004 static struct stasis_rest_handlers channels_channelId_dtmf = {
3005         .path_segment = "dtmf",
3006         .callbacks = {
3007                 [AST_HTTP_POST] = ast_ari_channels_send_dtmf_cb,
3008         },
3009         .num_children = 0,
3010         .children = {  }
3011 };
3012 /*! \brief REST handler for /api-docs/channels.{format} */
3013 static struct stasis_rest_handlers channels_channelId_mute = {
3014         .path_segment = "mute",
3015         .callbacks = {
3016                 [AST_HTTP_POST] = ast_ari_channels_mute_cb,
3017                 [AST_HTTP_DELETE] = ast_ari_channels_unmute_cb,
3018         },
3019         .num_children = 0,
3020         .children = {  }
3021 };
3022 /*! \brief REST handler for /api-docs/channels.{format} */
3023 static struct stasis_rest_handlers channels_channelId_hold = {
3024         .path_segment = "hold",
3025         .callbacks = {
3026                 [AST_HTTP_POST] = ast_ari_channels_hold_cb,
3027                 [AST_HTTP_DELETE] = ast_ari_channels_unhold_cb,
3028         },
3029         .num_children = 0,
3030         .children = {  }
3031 };
3032 /*! \brief REST handler for /api-docs/channels.{format} */
3033 static struct stasis_rest_handlers channels_channelId_moh = {
3034         .path_segment = "moh",
3035         .callbacks = {
3036                 [AST_HTTP_POST] = ast_ari_channels_start_moh_cb,
3037                 [AST_HTTP_DELETE] = ast_ari_channels_stop_moh_cb,
3038         },
3039         .num_children = 0,
3040         .children = {  }
3041 };
3042 /*! \brief REST handler for /api-docs/channels.{format} */
3043 static struct stasis_rest_handlers channels_channelId_silence = {
3044         .path_segment = "silence",
3045         .callbacks = {
3046                 [AST_HTTP_POST] = ast_ari_channels_start_silence_cb,
3047                 [AST_HTTP_DELETE] = ast_ari_channels_stop_silence_cb,
3048         },
3049         .num_children = 0,
3050         .children = {  }
3051 };
3052 /*! \brief REST handler for /api-docs/channels.{format} */
3053 static struct stasis_rest_handlers channels_channelId_play_playbackId = {
3054         .path_segment = "playbackId",
3055         .is_wildcard = 1,
3056         .callbacks = {
3057                 [AST_HTTP_POST] = ast_ari_channels_play_with_id_cb,
3058         },
3059         .num_children = 0,
3060         .children = {  }
3061 };
3062 /*! \brief REST handler for /api-docs/channels.{format} */
3063 static struct stasis_rest_handlers channels_channelId_play = {
3064         .path_segment = "play",
3065         .callbacks = {
3066                 [AST_HTTP_POST] = ast_ari_channels_play_cb,
3067         },
3068         .num_children = 1,
3069         .children = { &channels_channelId_play_playbackId, }
3070 };
3071 /*! \brief REST handler for /api-docs/channels.{format} */
3072 static struct stasis_rest_handlers channels_channelId_record = {
3073         .path_segment = "record",
3074         .callbacks = {
3075                 [AST_HTTP_POST] = ast_ari_channels_record_cb,
3076         },
3077         .num_children = 0,
3078         .children = {  }
3079 };
3080 /*! \brief REST handler for /api-docs/channels.{format} */
3081 static struct stasis_rest_handlers channels_channelId_variable = {
3082         .path_segment = "variable",
3083         .callbacks = {
3084                 [AST_HTTP_GET] = ast_ari_channels_get_channel_var_cb,
3085                 [AST_HTTP_POST] = ast_ari_channels_set_channel_var_cb,
3086         },
3087         .num_children = 0,
3088         .children = {  }
3089 };
3090 /*! \brief REST handler for /api-docs/channels.{format} */
3091 static struct stasis_rest_handlers channels_channelId_snoop_snoopId = {
3092         .path_segment = "snoopId",
3093         .is_wildcard = 1,
3094         .callbacks = {
3095                 [AST_HTTP_POST] = ast_ari_channels_snoop_channel_with_id_cb,
3096         },
3097         .num_children = 0,
3098         .children = {  }
3099 };
3100 /*! \brief REST handler for /api-docs/channels.{format} */
3101 static struct stasis_rest_handlers channels_channelId_snoop = {
3102         .path_segment = "snoop",
3103         .callbacks = {
3104                 [AST_HTTP_POST] = ast_ari_channels_snoop_channel_cb,
3105         },
3106         .num_children = 1,
3107         .children = { &channels_channelId_snoop_snoopId, }
3108 };
3109 /*! \brief REST handler for /api-docs/channels.{format} */
3110 static struct stasis_rest_handlers channels_channelId_dial = {
3111         .path_segment = "dial",
3112         .callbacks = {
3113                 [AST_HTTP_POST] = ast_ari_channels_dial_cb,
3114         },
3115         .num_children = 0,
3116         .children = {  }
3117 };
3118 /*! \brief REST handler for /api-docs/channels.{format} */
3119 static struct stasis_rest_handlers channels_channelId = {
3120         .path_segment = "channelId",
3121         .is_wildcard = 1,
3122         .callbacks = {
3123                 [AST_HTTP_GET] = ast_ari_channels_get_cb,
3124                 [AST_HTTP_POST] = ast_ari_channels_originate_with_id_cb,
3125                 [AST_HTTP_DELETE] = ast_ari_channels_hangup_cb,
3126         },
3127         .num_children = 14,
3128         .children = { &channels_channelId_continue,&channels_channelId_redirect,&channels_channelId_answer,&channels_channelId_ring,&channels_channelId_dtmf,&channels_channelId_mute,&channels_channelId_hold,&channels_channelId_moh,&channels_channelId_silence,&channels_channelId_play,&channels_channelId_record,&channels_channelId_variable,&channels_channelId_snoop,&channels_channelId_dial, }
3129 };
3130 /*! \brief REST handler for /api-docs/channels.{format} */
3131 static struct stasis_rest_handlers channels = {
3132         .path_segment = "channels",
3133         .callbacks = {
3134                 [AST_HTTP_GET] = ast_ari_channels_list_cb,
3135                 [AST_HTTP_POST] = ast_ari_channels_originate_cb,
3136         },
3137         .num_children = 2,
3138         .children = { &channels_create,&channels_channelId, }
3139 };
3140
3141 static int load_module(void)
3142 {
3143         int res = 0;
3144         stasis_app_ref();
3145         res |= ast_ari_add_handler(&channels);
3146         return res;
3147 }
3148
3149 static int unload_module(void)
3150 {
3151         ast_ari_remove_handler(&channels);