6b741b04c16b6d06ec78f231b5db24e9544c860b
[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_stasis</depend>
37         <support_level>core</support_level>
38  ***/
39
40 #include "asterisk.h"
41
42 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
43
44 #include "asterisk/app.h"
45 #include "asterisk/module.h"
46 #include "asterisk/stasis_app.h"
47 #include "ari/resource_channels.h"
48 #if defined(AST_DEVMODE)
49 #include "ari/ari_model_validators.h"
50 #endif
51
52 #define MAX_VALS 128
53
54 /*!
55  * \brief Parameter parsing callback for /channels.
56  * \param get_params GET parameters in the HTTP request.
57  * \param path_vars Path variables extracted from the request.
58  * \param headers HTTP headers.
59  * \param[out] response Response to the HTTP request.
60  */
61 static void ast_ari_channels_list_cb(
62         struct ast_tcptls_session_instance *ser,
63         struct ast_variable *get_params, struct ast_variable *path_vars,
64         struct ast_variable *headers, struct ast_ari_response *response)
65 {
66         struct ast_ari_channels_list_args args = {};
67         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
68 #if defined(AST_DEVMODE)
69         int is_valid;
70         int code;
71 #endif /* AST_DEVMODE */
72
73         ast_ari_channels_list(headers, &args, response);
74 #if defined(AST_DEVMODE)
75         code = response->response_code;
76
77         switch (code) {
78         case 0: /* Implementation is still a stub, or the code wasn't set */
79                 is_valid = response->message == NULL;
80                 break;
81         case 500: /* Internal Server Error */
82         case 501: /* Not Implemented */
83                 is_valid = 1;
84                 break;
85         default:
86                 if (200 <= code && code <= 299) {
87                         is_valid = ast_ari_validate_list(response->message,
88                                 ast_ari_validate_channel_fn());
89                 } else {
90                         ast_log(LOG_ERROR, "Invalid error response %d for /channels\n", code);
91                         is_valid = 0;
92                 }
93         }
94
95         if (!is_valid) {
96                 ast_log(LOG_ERROR, "Response validation failed for /channels\n");
97                 ast_ari_response_error(response, 500,
98                         "Internal Server Error", "Response validation failed");
99         }
100 #endif /* AST_DEVMODE */
101
102 fin: __attribute__((unused))
103         return;
104 }
105 /*!
106  * \brief Parameter parsing callback for /channels.
107  * \param get_params GET parameters in the HTTP request.
108  * \param path_vars Path variables extracted from the request.
109  * \param headers HTTP headers.
110  * \param[out] response Response to the HTTP request.
111  */
112 static void ast_ari_channels_originate_cb(
113         struct ast_tcptls_session_instance *ser,
114         struct ast_variable *get_params, struct ast_variable *path_vars,
115         struct ast_variable *headers, struct ast_ari_response *response)
116 {
117         struct ast_ari_channels_originate_args args = {};
118         struct ast_variable *i;
119         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
120 #if defined(AST_DEVMODE)
121         int is_valid;
122         int code;
123 #endif /* AST_DEVMODE */
124
125         for (i = get_params; i; i = i->next) {
126                 if (strcmp(i->name, "endpoint") == 0) {
127                         args.endpoint = (i->value);
128                 } else
129                 if (strcmp(i->name, "extension") == 0) {
130                         args.extension = (i->value);
131                 } else
132                 if (strcmp(i->name, "context") == 0) {
133                         args.context = (i->value);
134                 } else
135                 if (strcmp(i->name, "priority") == 0) {
136                         args.priority = atol(i->value);
137                 } else
138                 if (strcmp(i->name, "app") == 0) {
139                         args.app = (i->value);
140                 } else
141                 if (strcmp(i->name, "appArgs") == 0) {
142                         args.app_args = (i->value);
143                 } else
144                 if (strcmp(i->name, "callerId") == 0) {
145                         args.caller_id = (i->value);
146                 } else
147                 if (strcmp(i->name, "timeout") == 0) {
148                         args.timeout = atoi(i->value);
149                 } else
150                 {}
151         }
152         /* Look for a JSON request entity */
153         body = ast_http_get_json(ser, headers);
154         if (!body) {
155                 switch (errno) {
156                 case EFBIG:
157                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
158                         goto fin;
159                 case ENOMEM:
160                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
161                         goto fin;
162                 case EIO:
163                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
164                         goto fin;
165                 }
166         }
167         args.variables = ast_json_ref(body);
168         ast_ari_channels_originate(headers, &args, response);
169 #if defined(AST_DEVMODE)
170         code = response->response_code;
171
172         switch (code) {
173         case 0: /* Implementation is still a stub, or the code wasn't set */
174                 is_valid = response->message == NULL;
175                 break;
176         case 500: /* Internal Server Error */
177         case 501: /* Not Implemented */
178         case 400: /* Invalid parameters for originating a channel. */
179                 is_valid = 1;
180                 break;
181         default:
182                 if (200 <= code && code <= 299) {
183                         is_valid = ast_ari_validate_channel(
184                                 response->message);
185                 } else {
186                         ast_log(LOG_ERROR, "Invalid error response %d for /channels\n", code);
187                         is_valid = 0;
188                 }
189         }
190
191         if (!is_valid) {
192                 ast_log(LOG_ERROR, "Response validation failed for /channels\n");
193                 ast_ari_response_error(response, 500,
194                         "Internal Server Error", "Response validation failed");
195         }
196 #endif /* AST_DEVMODE */
197
198 fin: __attribute__((unused))
199         return;
200 }
201 /*!
202  * \brief Parameter parsing callback for /channels/{channelId}.
203  * \param get_params GET parameters in the HTTP request.
204  * \param path_vars Path variables extracted from the request.
205  * \param headers HTTP headers.
206  * \param[out] response Response to the HTTP request.
207  */
208 static void ast_ari_channels_get_cb(
209         struct ast_tcptls_session_instance *ser,
210         struct ast_variable *get_params, struct ast_variable *path_vars,
211         struct ast_variable *headers, struct ast_ari_response *response)
212 {
213         struct ast_ari_channels_get_args args = {};
214         struct ast_variable *i;
215         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
216 #if defined(AST_DEVMODE)
217         int is_valid;
218         int code;
219 #endif /* AST_DEVMODE */
220
221         for (i = path_vars; i; i = i->next) {
222                 if (strcmp(i->name, "channelId") == 0) {
223                         args.channel_id = (i->value);
224                 } else
225                 {}
226         }
227         ast_ari_channels_get(headers, &args, response);
228 #if defined(AST_DEVMODE)
229         code = response->response_code;
230
231         switch (code) {
232         case 0: /* Implementation is still a stub, or the code wasn't set */
233                 is_valid = response->message == NULL;
234                 break;
235         case 500: /* Internal Server Error */
236         case 501: /* Not Implemented */
237         case 404: /* Channel not found */
238                 is_valid = 1;
239                 break;
240         default:
241                 if (200 <= code && code <= 299) {
242                         is_valid = ast_ari_validate_channel(
243                                 response->message);
244                 } else {
245                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}\n", code);
246                         is_valid = 0;
247                 }
248         }
249
250         if (!is_valid) {
251                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}\n");
252                 ast_ari_response_error(response, 500,
253                         "Internal Server Error", "Response validation failed");
254         }
255 #endif /* AST_DEVMODE */
256
257 fin: __attribute__((unused))
258         return;
259 }
260 /*!
261  * \brief Parameter parsing callback for /channels/{channelId}.
262  * \param get_params GET parameters in the HTTP request.
263  * \param path_vars Path variables extracted from the request.
264  * \param headers HTTP headers.
265  * \param[out] response Response to the HTTP request.
266  */
267 static void ast_ari_channels_hangup_cb(
268         struct ast_tcptls_session_instance *ser,
269         struct ast_variable *get_params, struct ast_variable *path_vars,
270         struct ast_variable *headers, struct ast_ari_response *response)
271 {
272         struct ast_ari_channels_hangup_args args = {};
273         struct ast_variable *i;
274         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
275         struct ast_json *field;
276 #if defined(AST_DEVMODE)
277         int is_valid;
278         int code;
279 #endif /* AST_DEVMODE */
280
281         for (i = get_params; i; i = i->next) {
282                 if (strcmp(i->name, "reason") == 0) {
283                         args.reason = (i->value);
284                 } else
285                 {}
286         }
287         for (i = path_vars; i; i = i->next) {
288                 if (strcmp(i->name, "channelId") == 0) {
289                         args.channel_id = (i->value);
290                 } else
291                 {}
292         }
293         /* Look for a JSON request entity */
294         body = ast_http_get_json(ser, headers);
295         if (!body) {
296                 switch (errno) {
297                 case EFBIG:
298                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
299                         goto fin;
300                 case ENOMEM:
301                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
302                         goto fin;
303                 case EIO:
304                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
305                         goto fin;
306                 }
307         }
308         /* Parse query parameters out of it */
309         field = ast_json_object_get(body, "reason");
310         if (field) {
311                 args.reason = ast_json_string_get(field);
312         }
313         ast_ari_channels_hangup(headers, &args, response);
314 #if defined(AST_DEVMODE)
315         code = response->response_code;
316
317         switch (code) {
318         case 0: /* Implementation is still a stub, or the code wasn't set */
319                 is_valid = response->message == NULL;
320                 break;
321         case 500: /* Internal Server Error */
322         case 501: /* Not Implemented */
323         case 400: /* Invalid reason for hangup provided */
324         case 404: /* Channel not found */
325                 is_valid = 1;
326                 break;
327         default:
328                 if (200 <= code && code <= 299) {
329                         is_valid = ast_ari_validate_void(
330                                 response->message);
331                 } else {
332                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}\n", code);
333                         is_valid = 0;
334                 }
335         }
336
337         if (!is_valid) {
338                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}\n");
339                 ast_ari_response_error(response, 500,
340                         "Internal Server Error", "Response validation failed");
341         }
342 #endif /* AST_DEVMODE */
343
344 fin: __attribute__((unused))
345         return;
346 }
347 /*!
348  * \brief Parameter parsing callback for /channels/{channelId}/continue.
349  * \param get_params GET parameters in the HTTP request.
350  * \param path_vars Path variables extracted from the request.
351  * \param headers HTTP headers.
352  * \param[out] response Response to the HTTP request.
353  */
354 static void ast_ari_channels_continue_in_dialplan_cb(
355         struct ast_tcptls_session_instance *ser,
356         struct ast_variable *get_params, struct ast_variable *path_vars,
357         struct ast_variable *headers, struct ast_ari_response *response)
358 {
359         struct ast_ari_channels_continue_in_dialplan_args args = {};
360         struct ast_variable *i;
361         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
362         struct ast_json *field;
363 #if defined(AST_DEVMODE)
364         int is_valid;
365         int code;
366 #endif /* AST_DEVMODE */
367
368         for (i = get_params; i; i = i->next) {
369                 if (strcmp(i->name, "context") == 0) {
370                         args.context = (i->value);
371                 } else
372                 if (strcmp(i->name, "extension") == 0) {
373                         args.extension = (i->value);
374                 } else
375                 if (strcmp(i->name, "priority") == 0) {
376                         args.priority = atoi(i->value);
377                 } else
378                 {}
379         }
380         for (i = path_vars; i; i = i->next) {
381                 if (strcmp(i->name, "channelId") == 0) {
382                         args.channel_id = (i->value);
383                 } else
384                 {}
385         }
386         /* Look for a JSON request entity */
387         body = ast_http_get_json(ser, headers);
388         if (!body) {
389                 switch (errno) {
390                 case EFBIG:
391                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
392                         goto fin;
393                 case ENOMEM:
394                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
395                         goto fin;
396                 case EIO:
397                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
398                         goto fin;
399                 }
400         }
401         /* Parse query parameters out of it */
402         field = ast_json_object_get(body, "context");
403         if (field) {
404                 args.context = ast_json_string_get(field);
405         }
406         field = ast_json_object_get(body, "extension");
407         if (field) {
408                 args.extension = ast_json_string_get(field);
409         }
410         field = ast_json_object_get(body, "priority");
411         if (field) {
412                 args.priority = ast_json_integer_get(field);
413         }
414         ast_ari_channels_continue_in_dialplan(headers, &args, response);
415 #if defined(AST_DEVMODE)
416         code = response->response_code;
417
418         switch (code) {
419         case 0: /* Implementation is still a stub, or the code wasn't set */
420                 is_valid = response->message == NULL;
421                 break;
422         case 500: /* Internal Server Error */
423         case 501: /* Not Implemented */
424         case 404: /* Channel not found */
425         case 409: /* Channel not in a Stasis application */
426                 is_valid = 1;
427                 break;
428         default:
429                 if (200 <= code && code <= 299) {
430                         is_valid = ast_ari_validate_void(
431                                 response->message);
432                 } else {
433                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/continue\n", code);
434                         is_valid = 0;
435                 }
436         }
437
438         if (!is_valid) {
439                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/continue\n");
440                 ast_ari_response_error(response, 500,
441                         "Internal Server Error", "Response validation failed");
442         }
443 #endif /* AST_DEVMODE */
444
445 fin: __attribute__((unused))
446         return;
447 }
448 /*!
449  * \brief Parameter parsing callback for /channels/{channelId}/answer.
450  * \param get_params GET parameters in the HTTP request.
451  * \param path_vars Path variables extracted from the request.
452  * \param headers HTTP headers.
453  * \param[out] response Response to the HTTP request.
454  */
455 static void ast_ari_channels_answer_cb(
456         struct ast_tcptls_session_instance *ser,
457         struct ast_variable *get_params, struct ast_variable *path_vars,
458         struct ast_variable *headers, struct ast_ari_response *response)
459 {
460         struct ast_ari_channels_answer_args args = {};
461         struct ast_variable *i;
462         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
463 #if defined(AST_DEVMODE)
464         int is_valid;
465         int code;
466 #endif /* AST_DEVMODE */
467
468         for (i = path_vars; i; i = i->next) {
469                 if (strcmp(i->name, "channelId") == 0) {
470                         args.channel_id = (i->value);
471                 } else
472                 {}
473         }
474         ast_ari_channels_answer(headers, &args, response);
475 #if defined(AST_DEVMODE)
476         code = response->response_code;
477
478         switch (code) {
479         case 0: /* Implementation is still a stub, or the code wasn't set */
480                 is_valid = response->message == NULL;
481                 break;
482         case 500: /* Internal Server Error */
483         case 501: /* Not Implemented */
484         case 404: /* Channel not found */
485         case 409: /* Channel not in a Stasis application */
486                 is_valid = 1;
487                 break;
488         default:
489                 if (200 <= code && code <= 299) {
490                         is_valid = ast_ari_validate_void(
491                                 response->message);
492                 } else {
493                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/answer\n", code);
494                         is_valid = 0;
495                 }
496         }
497
498         if (!is_valid) {
499                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/answer\n");
500                 ast_ari_response_error(response, 500,
501                         "Internal Server Error", "Response validation failed");
502         }
503 #endif /* AST_DEVMODE */
504
505 fin: __attribute__((unused))
506         return;
507 }
508 /*!
509  * \brief Parameter parsing callback for /channels/{channelId}/ring.
510  * \param get_params GET parameters in the HTTP request.
511  * \param path_vars Path variables extracted from the request.
512  * \param headers HTTP headers.
513  * \param[out] response Response to the HTTP request.
514  */
515 static void ast_ari_channels_ring_cb(
516         struct ast_tcptls_session_instance *ser,
517         struct ast_variable *get_params, struct ast_variable *path_vars,
518         struct ast_variable *headers, struct ast_ari_response *response)
519 {
520         struct ast_ari_channels_ring_args args = {};
521         struct ast_variable *i;
522         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
523 #if defined(AST_DEVMODE)
524         int is_valid;
525         int code;
526 #endif /* AST_DEVMODE */
527
528         for (i = path_vars; i; i = i->next) {
529                 if (strcmp(i->name, "channelId") == 0) {
530                         args.channel_id = (i->value);
531                 } else
532                 {}
533         }
534         ast_ari_channels_ring(headers, &args, response);
535 #if defined(AST_DEVMODE)
536         code = response->response_code;
537
538         switch (code) {
539         case 0: /* Implementation is still a stub, or the code wasn't set */
540                 is_valid = response->message == NULL;
541                 break;
542         case 500: /* Internal Server Error */
543         case 501: /* Not Implemented */
544         case 404: /* Channel not found */
545         case 409: /* Channel not in a Stasis application */
546                 is_valid = 1;
547                 break;
548         default:
549                 if (200 <= code && code <= 299) {
550                         is_valid = ast_ari_validate_void(
551                                 response->message);
552                 } else {
553                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/ring\n", code);
554                         is_valid = 0;
555                 }
556         }
557
558         if (!is_valid) {
559                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/ring\n");
560                 ast_ari_response_error(response, 500,
561                         "Internal Server Error", "Response validation failed");
562         }
563 #endif /* AST_DEVMODE */
564
565 fin: __attribute__((unused))
566         return;
567 }
568 /*!
569  * \brief Parameter parsing callback for /channels/{channelId}/ring.
570  * \param get_params GET parameters in the HTTP request.
571  * \param path_vars Path variables extracted from the request.
572  * \param headers HTTP headers.
573  * \param[out] response Response to the HTTP request.
574  */
575 static void ast_ari_channels_ring_stop_cb(
576         struct ast_tcptls_session_instance *ser,
577         struct ast_variable *get_params, struct ast_variable *path_vars,
578         struct ast_variable *headers, struct ast_ari_response *response)
579 {
580         struct ast_ari_channels_ring_stop_args args = {};
581         struct ast_variable *i;
582         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
583 #if defined(AST_DEVMODE)
584         int is_valid;
585         int code;
586 #endif /* AST_DEVMODE */
587
588         for (i = path_vars; i; i = i->next) {
589                 if (strcmp(i->name, "channelId") == 0) {
590                         args.channel_id = (i->value);
591                 } else
592                 {}
593         }
594         ast_ari_channels_ring_stop(headers, &args, response);
595 #if defined(AST_DEVMODE)
596         code = response->response_code;
597
598         switch (code) {
599         case 0: /* Implementation is still a stub, or the code wasn't set */
600                 is_valid = response->message == NULL;
601                 break;
602         case 500: /* Internal Server Error */
603         case 501: /* Not Implemented */
604         case 404: /* Channel not found */
605         case 409: /* Channel not in a Stasis application */
606                 is_valid = 1;
607                 break;
608         default:
609                 if (200 <= code && code <= 299) {
610                         is_valid = ast_ari_validate_void(
611                                 response->message);
612                 } else {
613                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/ring\n", code);
614                         is_valid = 0;
615                 }
616         }
617
618         if (!is_valid) {
619                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/ring\n");
620                 ast_ari_response_error(response, 500,
621                         "Internal Server Error", "Response validation failed");
622         }
623 #endif /* AST_DEVMODE */
624
625 fin: __attribute__((unused))
626         return;
627 }
628 /*!
629  * \brief Parameter parsing callback for /channels/{channelId}/dtmf.
630  * \param get_params GET parameters in the HTTP request.
631  * \param path_vars Path variables extracted from the request.
632  * \param headers HTTP headers.
633  * \param[out] response Response to the HTTP request.
634  */
635 static void ast_ari_channels_send_dtmf_cb(
636         struct ast_tcptls_session_instance *ser,
637         struct ast_variable *get_params, struct ast_variable *path_vars,
638         struct ast_variable *headers, struct ast_ari_response *response)
639 {
640         struct ast_ari_channels_send_dtmf_args args = {};
641         struct ast_variable *i;
642         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
643         struct ast_json *field;
644 #if defined(AST_DEVMODE)
645         int is_valid;
646         int code;
647 #endif /* AST_DEVMODE */
648
649         for (i = get_params; i; i = i->next) {
650                 if (strcmp(i->name, "dtmf") == 0) {
651                         args.dtmf = (i->value);
652                 } else
653                 if (strcmp(i->name, "before") == 0) {
654                         args.before = atoi(i->value);
655                 } else
656                 if (strcmp(i->name, "between") == 0) {
657                         args.between = atoi(i->value);
658                 } else
659                 if (strcmp(i->name, "duration") == 0) {
660                         args.duration = atoi(i->value);
661                 } else
662                 if (strcmp(i->name, "after") == 0) {
663                         args.after = atoi(i->value);
664                 } else
665                 {}
666         }
667         for (i = path_vars; i; i = i->next) {
668                 if (strcmp(i->name, "channelId") == 0) {
669                         args.channel_id = (i->value);
670                 } else
671                 {}
672         }
673         /* Look for a JSON request entity */
674         body = ast_http_get_json(ser, headers);
675         if (!body) {
676                 switch (errno) {
677                 case EFBIG:
678                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
679                         goto fin;
680                 case ENOMEM:
681                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
682                         goto fin;
683                 case EIO:
684                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
685                         goto fin;
686                 }
687         }
688         /* Parse query parameters out of it */
689         field = ast_json_object_get(body, "dtmf");
690         if (field) {
691                 args.dtmf = ast_json_string_get(field);
692         }
693         field = ast_json_object_get(body, "before");
694         if (field) {
695                 args.before = ast_json_integer_get(field);
696         }
697         field = ast_json_object_get(body, "between");
698         if (field) {
699                 args.between = ast_json_integer_get(field);
700         }
701         field = ast_json_object_get(body, "duration");
702         if (field) {
703                 args.duration = ast_json_integer_get(field);
704         }
705         field = ast_json_object_get(body, "after");
706         if (field) {
707                 args.after = ast_json_integer_get(field);
708         }
709         ast_ari_channels_send_dtmf(headers, &args, response);
710 #if defined(AST_DEVMODE)
711         code = response->response_code;
712
713         switch (code) {
714         case 0: /* Implementation is still a stub, or the code wasn't set */
715                 is_valid = response->message == NULL;
716                 break;
717         case 500: /* Internal Server Error */
718         case 501: /* Not Implemented */
719         case 400: /* DTMF is required */
720         case 404: /* Channel not found */
721         case 409: /* Channel not in a Stasis application */
722                 is_valid = 1;
723                 break;
724         default:
725                 if (200 <= code && code <= 299) {
726                         is_valid = ast_ari_validate_void(
727                                 response->message);
728                 } else {
729                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/dtmf\n", code);
730                         is_valid = 0;
731                 }
732         }
733
734         if (!is_valid) {
735                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/dtmf\n");
736                 ast_ari_response_error(response, 500,
737                         "Internal Server Error", "Response validation failed");
738         }
739 #endif /* AST_DEVMODE */
740
741 fin: __attribute__((unused))
742         return;
743 }
744 /*!
745  * \brief Parameter parsing callback for /channels/{channelId}/mute.
746  * \param get_params GET parameters in the HTTP request.
747  * \param path_vars Path variables extracted from the request.
748  * \param headers HTTP headers.
749  * \param[out] response Response to the HTTP request.
750  */
751 static void ast_ari_channels_mute_cb(
752         struct ast_tcptls_session_instance *ser,
753         struct ast_variable *get_params, struct ast_variable *path_vars,
754         struct ast_variable *headers, struct ast_ari_response *response)
755 {
756         struct ast_ari_channels_mute_args args = {};
757         struct ast_variable *i;
758         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
759         struct ast_json *field;
760 #if defined(AST_DEVMODE)
761         int is_valid;
762         int code;
763 #endif /* AST_DEVMODE */
764
765         for (i = get_params; i; i = i->next) {
766                 if (strcmp(i->name, "direction") == 0) {
767                         args.direction = (i->value);
768                 } else
769                 {}
770         }
771         for (i = path_vars; i; i = i->next) {
772                 if (strcmp(i->name, "channelId") == 0) {
773                         args.channel_id = (i->value);
774                 } else
775                 {}
776         }
777         /* Look for a JSON request entity */
778         body = ast_http_get_json(ser, headers);
779         if (!body) {
780                 switch (errno) {
781                 case EFBIG:
782                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
783                         goto fin;
784                 case ENOMEM:
785                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
786                         goto fin;
787                 case EIO:
788                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
789                         goto fin;
790                 }
791         }
792         /* Parse query parameters out of it */
793         field = ast_json_object_get(body, "direction");
794         if (field) {
795                 args.direction = ast_json_string_get(field);
796         }
797         ast_ari_channels_mute(headers, &args, response);
798 #if defined(AST_DEVMODE)
799         code = response->response_code;
800
801         switch (code) {
802         case 0: /* Implementation is still a stub, or the code wasn't set */
803                 is_valid = response->message == NULL;
804                 break;
805         case 500: /* Internal Server Error */
806         case 501: /* Not Implemented */
807         case 404: /* Channel not found */
808         case 409: /* Channel not in a Stasis application */
809                 is_valid = 1;
810                 break;
811         default:
812                 if (200 <= code && code <= 299) {
813                         is_valid = ast_ari_validate_void(
814                                 response->message);
815                 } else {
816                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/mute\n", code);
817                         is_valid = 0;
818                 }
819         }
820
821         if (!is_valid) {
822                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/mute\n");
823                 ast_ari_response_error(response, 500,
824                         "Internal Server Error", "Response validation failed");
825         }
826 #endif /* AST_DEVMODE */
827
828 fin: __attribute__((unused))
829         return;
830 }
831 /*!
832  * \brief Parameter parsing callback for /channels/{channelId}/mute.
833  * \param get_params GET parameters in the HTTP request.
834  * \param path_vars Path variables extracted from the request.
835  * \param headers HTTP headers.
836  * \param[out] response Response to the HTTP request.
837  */
838 static void ast_ari_channels_unmute_cb(
839         struct ast_tcptls_session_instance *ser,
840         struct ast_variable *get_params, struct ast_variable *path_vars,
841         struct ast_variable *headers, struct ast_ari_response *response)
842 {
843         struct ast_ari_channels_unmute_args args = {};
844         struct ast_variable *i;
845         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
846         struct ast_json *field;
847 #if defined(AST_DEVMODE)
848         int is_valid;
849         int code;
850 #endif /* AST_DEVMODE */
851
852         for (i = get_params; i; i = i->next) {
853                 if (strcmp(i->name, "direction") == 0) {
854                         args.direction = (i->value);
855                 } else
856                 {}
857         }
858         for (i = path_vars; i; i = i->next) {
859                 if (strcmp(i->name, "channelId") == 0) {
860                         args.channel_id = (i->value);
861                 } else
862                 {}
863         }
864         /* Look for a JSON request entity */
865         body = ast_http_get_json(ser, headers);
866         if (!body) {
867                 switch (errno) {
868                 case EFBIG:
869                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
870                         goto fin;
871                 case ENOMEM:
872                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
873                         goto fin;
874                 case EIO:
875                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
876                         goto fin;
877                 }
878         }
879         /* Parse query parameters out of it */
880         field = ast_json_object_get(body, "direction");
881         if (field) {
882                 args.direction = ast_json_string_get(field);
883         }
884         ast_ari_channels_unmute(headers, &args, response);
885 #if defined(AST_DEVMODE)
886         code = response->response_code;
887
888         switch (code) {
889         case 0: /* Implementation is still a stub, or the code wasn't set */
890                 is_valid = response->message == NULL;
891                 break;
892         case 500: /* Internal Server Error */
893         case 501: /* Not Implemented */
894         case 404: /* Channel not found */
895         case 409: /* Channel not in a Stasis application */
896                 is_valid = 1;
897                 break;
898         default:
899                 if (200 <= code && code <= 299) {
900                         is_valid = ast_ari_validate_void(
901                                 response->message);
902                 } else {
903                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/mute\n", code);
904                         is_valid = 0;
905                 }
906         }
907
908         if (!is_valid) {
909                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/mute\n");
910                 ast_ari_response_error(response, 500,
911                         "Internal Server Error", "Response validation failed");
912         }
913 #endif /* AST_DEVMODE */
914
915 fin: __attribute__((unused))
916         return;
917 }
918 /*!
919  * \brief Parameter parsing callback for /channels/{channelId}/hold.
920  * \param get_params GET parameters in the HTTP request.
921  * \param path_vars Path variables extracted from the request.
922  * \param headers HTTP headers.
923  * \param[out] response Response to the HTTP request.
924  */
925 static void ast_ari_channels_hold_cb(
926         struct ast_tcptls_session_instance *ser,
927         struct ast_variable *get_params, struct ast_variable *path_vars,
928         struct ast_variable *headers, struct ast_ari_response *response)
929 {
930         struct ast_ari_channels_hold_args args = {};
931         struct ast_variable *i;
932         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
933 #if defined(AST_DEVMODE)
934         int is_valid;
935         int code;
936 #endif /* AST_DEVMODE */
937
938         for (i = path_vars; i; i = i->next) {
939                 if (strcmp(i->name, "channelId") == 0) {
940                         args.channel_id = (i->value);
941                 } else
942                 {}
943         }
944         ast_ari_channels_hold(headers, &args, response);
945 #if defined(AST_DEVMODE)
946         code = response->response_code;
947
948         switch (code) {
949         case 0: /* Implementation is still a stub, or the code wasn't set */
950                 is_valid = response->message == NULL;
951                 break;
952         case 500: /* Internal Server Error */
953         case 501: /* Not Implemented */
954         case 404: /* Channel not found */
955         case 409: /* Channel not in a Stasis application */
956                 is_valid = 1;
957                 break;
958         default:
959                 if (200 <= code && code <= 299) {
960                         is_valid = ast_ari_validate_void(
961                                 response->message);
962                 } else {
963                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/hold\n", code);
964                         is_valid = 0;
965                 }
966         }
967
968         if (!is_valid) {
969                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/hold\n");
970                 ast_ari_response_error(response, 500,
971                         "Internal Server Error", "Response validation failed");
972         }
973 #endif /* AST_DEVMODE */
974
975 fin: __attribute__((unused))
976         return;
977 }
978 /*!
979  * \brief Parameter parsing callback for /channels/{channelId}/hold.
980  * \param get_params GET parameters in the HTTP request.
981  * \param path_vars Path variables extracted from the request.
982  * \param headers HTTP headers.
983  * \param[out] response Response to the HTTP request.
984  */
985 static void ast_ari_channels_unhold_cb(
986         struct ast_tcptls_session_instance *ser,
987         struct ast_variable *get_params, struct ast_variable *path_vars,
988         struct ast_variable *headers, struct ast_ari_response *response)
989 {
990         struct ast_ari_channels_unhold_args args = {};
991         struct ast_variable *i;
992         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
993 #if defined(AST_DEVMODE)
994         int is_valid;
995         int code;
996 #endif /* AST_DEVMODE */
997
998         for (i = path_vars; i; i = i->next) {
999                 if (strcmp(i->name, "channelId") == 0) {
1000                         args.channel_id = (i->value);
1001                 } else
1002                 {}
1003         }
1004         ast_ari_channels_unhold(headers, &args, response);
1005 #if defined(AST_DEVMODE)
1006         code = response->response_code;
1007
1008         switch (code) {
1009         case 0: /* Implementation is still a stub, or the code wasn't set */
1010                 is_valid = response->message == NULL;
1011                 break;
1012         case 500: /* Internal Server Error */
1013         case 501: /* Not Implemented */
1014         case 404: /* Channel not found */
1015         case 409: /* Channel not in a Stasis application */
1016                 is_valid = 1;
1017                 break;
1018         default:
1019                 if (200 <= code && code <= 299) {
1020                         is_valid = ast_ari_validate_void(
1021                                 response->message);
1022                 } else {
1023                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/hold\n", code);
1024                         is_valid = 0;
1025                 }
1026         }
1027
1028         if (!is_valid) {
1029                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/hold\n");
1030                 ast_ari_response_error(response, 500,
1031                         "Internal Server Error", "Response validation failed");
1032         }
1033 #endif /* AST_DEVMODE */
1034
1035 fin: __attribute__((unused))
1036         return;
1037 }
1038 /*!
1039  * \brief Parameter parsing callback for /channels/{channelId}/moh.
1040  * \param get_params GET parameters in the HTTP request.
1041  * \param path_vars Path variables extracted from the request.
1042  * \param headers HTTP headers.
1043  * \param[out] response Response to the HTTP request.
1044  */
1045 static void ast_ari_channels_start_moh_cb(
1046         struct ast_tcptls_session_instance *ser,
1047         struct ast_variable *get_params, struct ast_variable *path_vars,
1048         struct ast_variable *headers, struct ast_ari_response *response)
1049 {
1050         struct ast_ari_channels_start_moh_args args = {};
1051         struct ast_variable *i;
1052         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1053         struct ast_json *field;
1054 #if defined(AST_DEVMODE)
1055         int is_valid;
1056         int code;
1057 #endif /* AST_DEVMODE */
1058
1059         for (i = get_params; i; i = i->next) {
1060                 if (strcmp(i->name, "mohClass") == 0) {
1061                         args.moh_class = (i->value);
1062                 } else
1063                 {}
1064         }
1065         for (i = path_vars; i; i = i->next) {
1066                 if (strcmp(i->name, "channelId") == 0) {
1067                         args.channel_id = (i->value);
1068                 } else
1069                 {}
1070         }
1071         /* Look for a JSON request entity */
1072         body = ast_http_get_json(ser, headers);
1073         if (!body) {
1074                 switch (errno) {
1075                 case EFBIG:
1076                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
1077                         goto fin;
1078                 case ENOMEM:
1079                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
1080                         goto fin;
1081                 case EIO:
1082                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
1083                         goto fin;
1084                 }
1085         }
1086         /* Parse query parameters out of it */
1087         field = ast_json_object_get(body, "mohClass");
1088         if (field) {
1089                 args.moh_class = ast_json_string_get(field);
1090         }
1091         ast_ari_channels_start_moh(headers, &args, response);
1092 #if defined(AST_DEVMODE)
1093         code = response->response_code;
1094
1095         switch (code) {
1096         case 0: /* Implementation is still a stub, or the code wasn't set */
1097                 is_valid = response->message == NULL;
1098                 break;
1099         case 500: /* Internal Server Error */
1100         case 501: /* Not Implemented */
1101         case 404: /* Channel not found */
1102         case 409: /* Channel not in a Stasis application */
1103                 is_valid = 1;
1104                 break;
1105         default:
1106                 if (200 <= code && code <= 299) {
1107                         is_valid = ast_ari_validate_void(
1108                                 response->message);
1109                 } else {
1110                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/moh\n", code);
1111                         is_valid = 0;
1112                 }
1113         }
1114
1115         if (!is_valid) {
1116                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/moh\n");
1117                 ast_ari_response_error(response, 500,
1118                         "Internal Server Error", "Response validation failed");
1119         }
1120 #endif /* AST_DEVMODE */
1121
1122 fin: __attribute__((unused))
1123         return;
1124 }
1125 /*!
1126  * \brief Parameter parsing callback for /channels/{channelId}/moh.
1127  * \param get_params GET parameters in the HTTP request.
1128  * \param path_vars Path variables extracted from the request.
1129  * \param headers HTTP headers.
1130  * \param[out] response Response to the HTTP request.
1131  */
1132 static void ast_ari_channels_stop_moh_cb(
1133         struct ast_tcptls_session_instance *ser,
1134         struct ast_variable *get_params, struct ast_variable *path_vars,
1135         struct ast_variable *headers, struct ast_ari_response *response)
1136 {
1137         struct ast_ari_channels_stop_moh_args args = {};
1138         struct ast_variable *i;
1139         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1140 #if defined(AST_DEVMODE)
1141         int is_valid;
1142         int code;
1143 #endif /* AST_DEVMODE */
1144
1145         for (i = path_vars; i; i = i->next) {
1146                 if (strcmp(i->name, "channelId") == 0) {
1147                         args.channel_id = (i->value);
1148                 } else
1149                 {}
1150         }
1151         ast_ari_channels_stop_moh(headers, &args, response);
1152 #if defined(AST_DEVMODE)
1153         code = response->response_code;
1154
1155         switch (code) {
1156         case 0: /* Implementation is still a stub, or the code wasn't set */
1157                 is_valid = response->message == NULL;
1158                 break;
1159         case 500: /* Internal Server Error */
1160         case 501: /* Not Implemented */
1161         case 404: /* Channel not found */
1162         case 409: /* Channel not in a Stasis application */
1163                 is_valid = 1;
1164                 break;
1165         default:
1166                 if (200 <= code && code <= 299) {
1167                         is_valid = ast_ari_validate_void(
1168                                 response->message);
1169                 } else {
1170                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/moh\n", code);
1171                         is_valid = 0;
1172                 }
1173         }
1174
1175         if (!is_valid) {
1176                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/moh\n");
1177                 ast_ari_response_error(response, 500,
1178                         "Internal Server Error", "Response validation failed");
1179         }
1180 #endif /* AST_DEVMODE */
1181
1182 fin: __attribute__((unused))
1183         return;
1184 }
1185 /*!
1186  * \brief Parameter parsing callback for /channels/{channelId}/silence.
1187  * \param get_params GET parameters in the HTTP request.
1188  * \param path_vars Path variables extracted from the request.
1189  * \param headers HTTP headers.
1190  * \param[out] response Response to the HTTP request.
1191  */
1192 static void ast_ari_channels_start_silence_cb(
1193         struct ast_tcptls_session_instance *ser,
1194         struct ast_variable *get_params, struct ast_variable *path_vars,
1195         struct ast_variable *headers, struct ast_ari_response *response)
1196 {
1197         struct ast_ari_channels_start_silence_args args = {};
1198         struct ast_variable *i;
1199         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1200 #if defined(AST_DEVMODE)
1201         int is_valid;
1202         int code;
1203 #endif /* AST_DEVMODE */
1204
1205         for (i = path_vars; i; i = i->next) {
1206                 if (strcmp(i->name, "channelId") == 0) {
1207                         args.channel_id = (i->value);
1208                 } else
1209                 {}
1210         }
1211         ast_ari_channels_start_silence(headers, &args, response);
1212 #if defined(AST_DEVMODE)
1213         code = response->response_code;
1214
1215         switch (code) {
1216         case 0: /* Implementation is still a stub, or the code wasn't set */
1217                 is_valid = response->message == NULL;
1218                 break;
1219         case 500: /* Internal Server Error */
1220         case 501: /* Not Implemented */
1221         case 404: /* Channel not found */
1222         case 409: /* Channel not in a Stasis application */
1223                 is_valid = 1;
1224                 break;
1225         default:
1226                 if (200 <= code && code <= 299) {
1227                         is_valid = ast_ari_validate_void(
1228                                 response->message);
1229                 } else {
1230                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/silence\n", code);
1231                         is_valid = 0;
1232                 }
1233         }
1234
1235         if (!is_valid) {
1236                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/silence\n");
1237                 ast_ari_response_error(response, 500,
1238                         "Internal Server Error", "Response validation failed");
1239         }
1240 #endif /* AST_DEVMODE */
1241
1242 fin: __attribute__((unused))
1243         return;
1244 }
1245 /*!
1246  * \brief Parameter parsing callback for /channels/{channelId}/silence.
1247  * \param get_params GET parameters in the HTTP request.
1248  * \param path_vars Path variables extracted from the request.
1249  * \param headers HTTP headers.
1250  * \param[out] response Response to the HTTP request.
1251  */
1252 static void ast_ari_channels_stop_silence_cb(
1253         struct ast_tcptls_session_instance *ser,
1254         struct ast_variable *get_params, struct ast_variable *path_vars,
1255         struct ast_variable *headers, struct ast_ari_response *response)
1256 {
1257         struct ast_ari_channels_stop_silence_args args = {};
1258         struct ast_variable *i;
1259         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1260 #if defined(AST_DEVMODE)
1261         int is_valid;
1262         int code;
1263 #endif /* AST_DEVMODE */
1264
1265         for (i = path_vars; i; i = i->next) {
1266                 if (strcmp(i->name, "channelId") == 0) {
1267                         args.channel_id = (i->value);
1268                 } else
1269                 {}
1270         }
1271         ast_ari_channels_stop_silence(headers, &args, response);
1272 #if defined(AST_DEVMODE)
1273         code = response->response_code;
1274
1275         switch (code) {
1276         case 0: /* Implementation is still a stub, or the code wasn't set */
1277                 is_valid = response->message == NULL;
1278                 break;
1279         case 500: /* Internal Server Error */
1280         case 501: /* Not Implemented */
1281         case 404: /* Channel not found */
1282         case 409: /* Channel not in a Stasis application */
1283                 is_valid = 1;
1284                 break;
1285         default:
1286                 if (200 <= code && code <= 299) {
1287                         is_valid = ast_ari_validate_void(
1288                                 response->message);
1289                 } else {
1290                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/silence\n", code);
1291                         is_valid = 0;
1292                 }
1293         }
1294
1295         if (!is_valid) {
1296                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/silence\n");
1297                 ast_ari_response_error(response, 500,
1298                         "Internal Server Error", "Response validation failed");
1299         }
1300 #endif /* AST_DEVMODE */
1301
1302 fin: __attribute__((unused))
1303         return;
1304 }
1305 /*!
1306  * \brief Parameter parsing callback for /channels/{channelId}/play.
1307  * \param get_params GET parameters in the HTTP request.
1308  * \param path_vars Path variables extracted from the request.
1309  * \param headers HTTP headers.
1310  * \param[out] response Response to the HTTP request.
1311  */
1312 static void ast_ari_channels_play_cb(
1313         struct ast_tcptls_session_instance *ser,
1314         struct ast_variable *get_params, struct ast_variable *path_vars,
1315         struct ast_variable *headers, struct ast_ari_response *response)
1316 {
1317         struct ast_ari_channels_play_args args = {};
1318         struct ast_variable *i;
1319         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1320         struct ast_json *field;
1321 #if defined(AST_DEVMODE)
1322         int is_valid;
1323         int code;
1324 #endif /* AST_DEVMODE */
1325
1326         for (i = get_params; i; i = i->next) {
1327                 if (strcmp(i->name, "media") == 0) {
1328                         args.media = (i->value);
1329                 } else
1330                 if (strcmp(i->name, "lang") == 0) {
1331                         args.lang = (i->value);
1332                 } else
1333                 if (strcmp(i->name, "offsetms") == 0) {
1334                         args.offsetms = atoi(i->value);
1335                 } else
1336                 if (strcmp(i->name, "skipms") == 0) {
1337                         args.skipms = atoi(i->value);
1338                 } else
1339                 {}
1340         }
1341         for (i = path_vars; i; i = i->next) {
1342                 if (strcmp(i->name, "channelId") == 0) {
1343                         args.channel_id = (i->value);
1344                 } else
1345                 {}
1346         }
1347         /* Look for a JSON request entity */
1348         body = ast_http_get_json(ser, headers);
1349         if (!body) {
1350                 switch (errno) {
1351                 case EFBIG:
1352                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
1353                         goto fin;
1354                 case ENOMEM:
1355                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
1356                         goto fin;
1357                 case EIO:
1358                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
1359                         goto fin;
1360                 }
1361         }
1362         /* Parse query parameters out of it */
1363         field = ast_json_object_get(body, "media");
1364         if (field) {
1365                 args.media = ast_json_string_get(field);
1366         }
1367         field = ast_json_object_get(body, "lang");
1368         if (field) {
1369                 args.lang = ast_json_string_get(field);
1370         }
1371         field = ast_json_object_get(body, "offsetms");
1372         if (field) {
1373                 args.offsetms = ast_json_integer_get(field);
1374         }
1375         field = ast_json_object_get(body, "skipms");
1376         if (field) {
1377                 args.skipms = ast_json_integer_get(field);
1378         }
1379         ast_ari_channels_play(headers, &args, response);
1380 #if defined(AST_DEVMODE)
1381         code = response->response_code;
1382
1383         switch (code) {
1384         case 0: /* Implementation is still a stub, or the code wasn't set */
1385                 is_valid = response->message == NULL;
1386                 break;
1387         case 500: /* Internal Server Error */
1388         case 501: /* Not Implemented */
1389         case 404: /* Channel not found */
1390         case 409: /* Channel not in a Stasis application */
1391                 is_valid = 1;
1392                 break;
1393         default:
1394                 if (200 <= code && code <= 299) {
1395                         is_valid = ast_ari_validate_playback(
1396                                 response->message);
1397                 } else {
1398                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/play\n", code);
1399                         is_valid = 0;
1400                 }
1401         }
1402
1403         if (!is_valid) {
1404                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/play\n");
1405                 ast_ari_response_error(response, 500,
1406                         "Internal Server Error", "Response validation failed");
1407         }
1408 #endif /* AST_DEVMODE */
1409
1410 fin: __attribute__((unused))
1411         return;
1412 }
1413 /*!
1414  * \brief Parameter parsing callback for /channels/{channelId}/record.
1415  * \param get_params GET parameters in the HTTP request.
1416  * \param path_vars Path variables extracted from the request.
1417  * \param headers HTTP headers.
1418  * \param[out] response Response to the HTTP request.
1419  */
1420 static void ast_ari_channels_record_cb(
1421         struct ast_tcptls_session_instance *ser,
1422         struct ast_variable *get_params, struct ast_variable *path_vars,
1423         struct ast_variable *headers, struct ast_ari_response *response)
1424 {
1425         struct ast_ari_channels_record_args args = {};
1426         struct ast_variable *i;
1427         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1428         struct ast_json *field;
1429 #if defined(AST_DEVMODE)
1430         int is_valid;
1431         int code;
1432 #endif /* AST_DEVMODE */
1433
1434         for (i = get_params; i; i = i->next) {
1435                 if (strcmp(i->name, "name") == 0) {
1436                         args.name = (i->value);
1437                 } else
1438                 if (strcmp(i->name, "format") == 0) {
1439                         args.format = (i->value);
1440                 } else
1441                 if (strcmp(i->name, "maxDurationSeconds") == 0) {
1442                         args.max_duration_seconds = atoi(i->value);
1443                 } else
1444                 if (strcmp(i->name, "maxSilenceSeconds") == 0) {
1445                         args.max_silence_seconds = atoi(i->value);
1446                 } else
1447                 if (strcmp(i->name, "ifExists") == 0) {
1448                         args.if_exists = (i->value);
1449                 } else
1450                 if (strcmp(i->name, "beep") == 0) {
1451                         args.beep = ast_true(i->value);
1452                 } else
1453                 if (strcmp(i->name, "terminateOn") == 0) {
1454                         args.terminate_on = (i->value);
1455                 } else
1456                 {}
1457         }
1458         for (i = path_vars; i; i = i->next) {
1459                 if (strcmp(i->name, "channelId") == 0) {
1460                         args.channel_id = (i->value);
1461                 } else
1462                 {}
1463         }
1464         /* Look for a JSON request entity */
1465         body = ast_http_get_json(ser, headers);
1466         if (!body) {
1467                 switch (errno) {
1468                 case EFBIG:
1469                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
1470                         goto fin;
1471                 case ENOMEM:
1472                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
1473                         goto fin;
1474                 case EIO:
1475                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
1476                         goto fin;
1477                 }
1478         }
1479         /* Parse query parameters out of it */
1480         field = ast_json_object_get(body, "name");
1481         if (field) {
1482                 args.name = ast_json_string_get(field);
1483         }
1484         field = ast_json_object_get(body, "format");
1485         if (field) {
1486                 args.format = ast_json_string_get(field);
1487         }
1488         field = ast_json_object_get(body, "maxDurationSeconds");
1489         if (field) {
1490                 args.max_duration_seconds = ast_json_integer_get(field);
1491         }
1492         field = ast_json_object_get(body, "maxSilenceSeconds");
1493         if (field) {
1494                 args.max_silence_seconds = ast_json_integer_get(field);
1495         }
1496         field = ast_json_object_get(body, "ifExists");
1497         if (field) {
1498                 args.if_exists = ast_json_string_get(field);
1499         }
1500         field = ast_json_object_get(body, "beep");
1501         if (field) {
1502                 args.beep = ast_json_is_true(field);
1503         }
1504         field = ast_json_object_get(body, "terminateOn");
1505         if (field) {
1506                 args.terminate_on = ast_json_string_get(field);
1507         }
1508         ast_ari_channels_record(headers, &args, response);
1509 #if defined(AST_DEVMODE)
1510         code = response->response_code;
1511
1512         switch (code) {
1513         case 0: /* Implementation is still a stub, or the code wasn't set */
1514                 is_valid = response->message == NULL;
1515                 break;
1516         case 500: /* Internal Server Error */
1517         case 501: /* Not Implemented */
1518         case 400: /* Invalid parameters */
1519         case 404: /* Channel not found */
1520         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 */
1521         case 422: /* The format specified is unknown on this system */
1522                 is_valid = 1;
1523                 break;
1524         default:
1525                 if (200 <= code && code <= 299) {
1526                         is_valid = ast_ari_validate_live_recording(
1527                                 response->message);
1528                 } else {
1529                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/record\n", code);
1530                         is_valid = 0;
1531                 }
1532         }
1533
1534         if (!is_valid) {
1535                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/record\n");
1536                 ast_ari_response_error(response, 500,
1537                         "Internal Server Error", "Response validation failed");
1538         }
1539 #endif /* AST_DEVMODE */
1540
1541 fin: __attribute__((unused))
1542         return;
1543 }
1544 /*!
1545  * \brief Parameter parsing callback for /channels/{channelId}/variable.
1546  * \param get_params GET parameters in the HTTP request.
1547  * \param path_vars Path variables extracted from the request.
1548  * \param headers HTTP headers.
1549  * \param[out] response Response to the HTTP request.
1550  */
1551 static void ast_ari_channels_get_channel_var_cb(
1552         struct ast_tcptls_session_instance *ser,
1553         struct ast_variable *get_params, struct ast_variable *path_vars,
1554         struct ast_variable *headers, struct ast_ari_response *response)
1555 {
1556         struct ast_ari_channels_get_channel_var_args args = {};
1557         struct ast_variable *i;
1558         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1559         struct ast_json *field;
1560 #if defined(AST_DEVMODE)
1561         int is_valid;
1562         int code;
1563 #endif /* AST_DEVMODE */
1564
1565         for (i = get_params; i; i = i->next) {
1566                 if (strcmp(i->name, "variable") == 0) {
1567                         args.variable = (i->value);
1568                 } else
1569                 {}
1570         }
1571         for (i = path_vars; i; i = i->next) {
1572                 if (strcmp(i->name, "channelId") == 0) {
1573                         args.channel_id = (i->value);
1574                 } else
1575                 {}
1576         }
1577         /* Look for a JSON request entity */
1578         body = ast_http_get_json(ser, headers);
1579         if (!body) {
1580                 switch (errno) {
1581                 case EFBIG:
1582                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
1583                         goto fin;
1584                 case ENOMEM:
1585                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
1586                         goto fin;
1587                 case EIO:
1588                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
1589                         goto fin;
1590                 }
1591         }
1592         /* Parse query parameters out of it */
1593         field = ast_json_object_get(body, "variable");
1594         if (field) {
1595                 args.variable = ast_json_string_get(field);
1596         }
1597         ast_ari_channels_get_channel_var(headers, &args, response);
1598 #if defined(AST_DEVMODE)
1599         code = response->response_code;
1600
1601         switch (code) {
1602         case 0: /* Implementation is still a stub, or the code wasn't set */
1603                 is_valid = response->message == NULL;
1604                 break;
1605         case 500: /* Internal Server Error */
1606         case 501: /* Not Implemented */
1607         case 400: /* Missing variable parameter. */
1608         case 404: /* Channel not found */
1609         case 409: /* Channel not in a Stasis application */
1610                 is_valid = 1;
1611                 break;
1612         default:
1613                 if (200 <= code && code <= 299) {
1614                         is_valid = ast_ari_validate_variable(
1615                                 response->message);
1616                 } else {
1617                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/variable\n", code);
1618                         is_valid = 0;
1619                 }
1620         }
1621
1622         if (!is_valid) {
1623                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/variable\n");
1624                 ast_ari_response_error(response, 500,
1625                         "Internal Server Error", "Response validation failed");
1626         }
1627 #endif /* AST_DEVMODE */
1628
1629 fin: __attribute__((unused))
1630         return;
1631 }
1632 /*!
1633  * \brief Parameter parsing callback for /channels/{channelId}/variable.
1634  * \param get_params GET parameters in the HTTP request.
1635  * \param path_vars Path variables extracted from the request.
1636  * \param headers HTTP headers.
1637  * \param[out] response Response to the HTTP request.
1638  */
1639 static void ast_ari_channels_set_channel_var_cb(
1640         struct ast_tcptls_session_instance *ser,
1641         struct ast_variable *get_params, struct ast_variable *path_vars,
1642         struct ast_variable *headers, struct ast_ari_response *response)
1643 {
1644         struct ast_ari_channels_set_channel_var_args args = {};
1645         struct ast_variable *i;
1646         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1647         struct ast_json *field;
1648 #if defined(AST_DEVMODE)
1649         int is_valid;
1650         int code;
1651 #endif /* AST_DEVMODE */
1652
1653         for (i = get_params; i; i = i->next) {
1654                 if (strcmp(i->name, "variable") == 0) {
1655                         args.variable = (i->value);
1656                 } else
1657                 if (strcmp(i->name, "value") == 0) {
1658                         args.value = (i->value);
1659                 } else
1660                 {}
1661         }
1662         for (i = path_vars; i; i = i->next) {
1663                 if (strcmp(i->name, "channelId") == 0) {
1664                         args.channel_id = (i->value);
1665                 } else
1666                 {}
1667         }
1668         /* Look for a JSON request entity */
1669         body = ast_http_get_json(ser, headers);
1670         if (!body) {
1671                 switch (errno) {
1672                 case EFBIG:
1673                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
1674                         goto fin;
1675                 case ENOMEM:
1676                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
1677                         goto fin;
1678                 case EIO:
1679                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
1680                         goto fin;
1681                 }
1682         }
1683         /* Parse query parameters out of it */
1684         field = ast_json_object_get(body, "variable");
1685         if (field) {
1686                 args.variable = ast_json_string_get(field);
1687         }
1688         field = ast_json_object_get(body, "value");
1689         if (field) {
1690                 args.value = ast_json_string_get(field);
1691         }
1692         ast_ari_channels_set_channel_var(headers, &args, response);
1693 #if defined(AST_DEVMODE)
1694         code = response->response_code;
1695
1696         switch (code) {
1697         case 0: /* Implementation is still a stub, or the code wasn't set */
1698                 is_valid = response->message == NULL;
1699                 break;
1700         case 500: /* Internal Server Error */
1701         case 501: /* Not Implemented */
1702         case 400: /* Missing variable parameter. */
1703         case 404: /* Channel not found */
1704         case 409: /* Channel not in a Stasis application */
1705                 is_valid = 1;
1706                 break;
1707         default:
1708                 if (200 <= code && code <= 299) {
1709                         is_valid = ast_ari_validate_void(
1710                                 response->message);
1711                 } else {
1712                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/variable\n", code);
1713                         is_valid = 0;
1714                 }
1715         }
1716
1717         if (!is_valid) {
1718                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/variable\n");
1719                 ast_ari_response_error(response, 500,
1720                         "Internal Server Error", "Response validation failed");
1721         }
1722 #endif /* AST_DEVMODE */
1723
1724 fin: __attribute__((unused))
1725         return;
1726 }
1727 /*!
1728  * \brief Parameter parsing callback for /channels/{channelId}/snoop.
1729  * \param get_params GET parameters in the HTTP request.
1730  * \param path_vars Path variables extracted from the request.
1731  * \param headers HTTP headers.
1732  * \param[out] response Response to the HTTP request.
1733  */
1734 static void ast_ari_channels_snoop_channel_cb(
1735         struct ast_tcptls_session_instance *ser,
1736         struct ast_variable *get_params, struct ast_variable *path_vars,
1737         struct ast_variable *headers, struct ast_ari_response *response)
1738 {
1739         struct ast_ari_channels_snoop_channel_args args = {};
1740         struct ast_variable *i;
1741         RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
1742         struct ast_json *field;
1743 #if defined(AST_DEVMODE)
1744         int is_valid;
1745         int code;
1746 #endif /* AST_DEVMODE */
1747
1748         for (i = get_params; i; i = i->next) {
1749                 if (strcmp(i->name, "spy") == 0) {
1750                         args.spy = (i->value);
1751                 } else
1752                 if (strcmp(i->name, "whisper") == 0) {
1753                         args.whisper = (i->value);
1754                 } else
1755                 if (strcmp(i->name, "app") == 0) {
1756                         args.app = (i->value);
1757                 } else
1758                 if (strcmp(i->name, "appArgs") == 0) {
1759                         args.app_args = (i->value);
1760                 } else
1761                 {}
1762         }
1763         for (i = path_vars; i; i = i->next) {
1764                 if (strcmp(i->name, "channelId") == 0) {
1765                         args.channel_id = (i->value);
1766                 } else
1767                 {}
1768         }
1769         /* Look for a JSON request entity */
1770         body = ast_http_get_json(ser, headers);
1771         if (!body) {
1772                 switch (errno) {
1773                 case EFBIG:
1774                         ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
1775                         goto fin;
1776                 case ENOMEM:
1777                         ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
1778                         goto fin;
1779                 case EIO:
1780                         ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
1781                         goto fin;
1782                 }
1783         }
1784         /* Parse query parameters out of it */
1785         field = ast_json_object_get(body, "spy");
1786         if (field) {
1787                 args.spy = ast_json_string_get(field);
1788         }
1789         field = ast_json_object_get(body, "whisper");
1790         if (field) {
1791                 args.whisper = ast_json_string_get(field);
1792         }
1793         field = ast_json_object_get(body, "app");
1794         if (field) {
1795                 args.app = ast_json_string_get(field);
1796         }
1797         field = ast_json_object_get(body, "appArgs");
1798         if (field) {
1799                 args.app_args = ast_json_string_get(field);
1800         }
1801         ast_ari_channels_snoop_channel(headers, &args, response);
1802 #if defined(AST_DEVMODE)
1803         code = response->response_code;
1804
1805         switch (code) {
1806         case 0: /* Implementation is still a stub, or the code wasn't set */
1807                 is_valid = response->message == NULL;
1808                 break;
1809         case 500: /* Internal Server Error */
1810         case 501: /* Not Implemented */
1811         case 400: /* Invalid parameters */
1812         case 404: /* Channel not found */
1813                 is_valid = 1;
1814                 break;
1815         default:
1816                 if (200 <= code && code <= 299) {
1817                         is_valid = ast_ari_validate_channel(
1818                                 response->message);
1819                 } else {
1820                         ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/snoop\n", code);
1821                         is_valid = 0;
1822                 }
1823         }
1824
1825         if (!is_valid) {
1826                 ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/snoop\n");
1827                 ast_ari_response_error(response, 500,
1828                         "Internal Server Error", "Response validation failed");
1829         }
1830 #endif /* AST_DEVMODE */
1831
1832 fin: __attribute__((unused))
1833         return;
1834 }
1835
1836 /*! \brief REST handler for /api-docs/channels.{format} */
1837 static struct stasis_rest_handlers channels_channelId_continue = {
1838         .path_segment = "continue",
1839         .callbacks = {
1840                 [AST_HTTP_POST] = ast_ari_channels_continue_in_dialplan_cb,
1841         },
1842         .num_children = 0,
1843         .children = {  }
1844 };
1845 /*! \brief REST handler for /api-docs/channels.{format} */
1846 static struct stasis_rest_handlers channels_channelId_answer = {
1847         .path_segment = "answer",
1848         .callbacks = {
1849                 [AST_HTTP_POST] = ast_ari_channels_answer_cb,
1850         },
1851         .num_children = 0,
1852         .children = {  }
1853 };
1854 /*! \brief REST handler for /api-docs/channels.{format} */
1855 static struct stasis_rest_handlers channels_channelId_ring = {
1856         .path_segment = "ring",
1857         .callbacks = {
1858                 [AST_HTTP_POST] = ast_ari_channels_ring_cb,
1859                 [AST_HTTP_DELETE] = ast_ari_channels_ring_stop_cb,
1860         },
1861         .num_children = 0,
1862         .children = {  }
1863 };
1864 /*! \brief REST handler for /api-docs/channels.{format} */
1865 static struct stasis_rest_handlers channels_channelId_dtmf = {
1866         .path_segment = "dtmf",
1867         .callbacks = {
1868                 [AST_HTTP_POST] = ast_ari_channels_send_dtmf_cb,
1869         },
1870         .num_children = 0,
1871         .children = {  }
1872 };
1873 /*! \brief REST handler for /api-docs/channels.{format} */
1874 static struct stasis_rest_handlers channels_channelId_mute = {
1875         .path_segment = "mute",
1876         .callbacks = {
1877                 [AST_HTTP_POST] = ast_ari_channels_mute_cb,
1878                 [AST_HTTP_DELETE] = ast_ari_channels_unmute_cb,
1879         },
1880         .num_children = 0,
1881         .children = {  }
1882 };
1883 /*! \brief REST handler for /api-docs/channels.{format} */
1884 static struct stasis_rest_handlers channels_channelId_hold = {
1885         .path_segment = "hold",
1886         .callbacks = {
1887                 [AST_HTTP_POST] = ast_ari_channels_hold_cb,
1888                 [AST_HTTP_DELETE] = ast_ari_channels_unhold_cb,
1889         },
1890         .num_children = 0,
1891         .children = {  }
1892 };
1893 /*! \brief REST handler for /api-docs/channels.{format} */
1894 static struct stasis_rest_handlers channels_channelId_moh = {
1895         .path_segment = "moh",
1896         .callbacks = {
1897                 [AST_HTTP_POST] = ast_ari_channels_start_moh_cb,
1898                 [AST_HTTP_DELETE] = ast_ari_channels_stop_moh_cb,
1899         },
1900         .num_children = 0,
1901         .children = {  }
1902 };
1903 /*! \brief REST handler for /api-docs/channels.{format} */
1904 static struct stasis_rest_handlers channels_channelId_silence = {
1905         .path_segment = "silence",
1906         .callbacks = {
1907                 [AST_HTTP_POST] = ast_ari_channels_start_silence_cb,
1908                 [AST_HTTP_DELETE] = ast_ari_channels_stop_silence_cb,
1909         },
1910         .num_children = 0,
1911         .children = {  }
1912 };
1913 /*! \brief REST handler for /api-docs/channels.{format} */
1914 static struct stasis_rest_handlers channels_channelId_play = {
1915         .path_segment = "play",
1916         .callbacks = {
1917                 [AST_HTTP_POST] = ast_ari_channels_play_cb,
1918         },
1919         .num_children = 0,
1920         .children = {  }
1921 };
1922 /*! \brief REST handler for /api-docs/channels.{format} */
1923 static struct stasis_rest_handlers channels_channelId_record = {
1924         .path_segment = "record",
1925         .callbacks = {
1926                 [AST_HTTP_POST] = ast_ari_channels_record_cb,
1927         },
1928         .num_children = 0,
1929         .children = {  }
1930 };
1931 /*! \brief REST handler for /api-docs/channels.{format} */
1932 static struct stasis_rest_handlers channels_channelId_variable = {
1933         .path_segment = "variable",
1934         .callbacks = {
1935                 [AST_HTTP_GET] = ast_ari_channels_get_channel_var_cb,
1936                 [AST_HTTP_POST] = ast_ari_channels_set_channel_var_cb,
1937         },
1938         .num_children = 0,
1939         .children = {  }
1940 };
1941 /*! \brief REST handler for /api-docs/channels.{format} */
1942 static struct stasis_rest_handlers channels_channelId_snoop = {
1943         .path_segment = "snoop",
1944         .callbacks = {
1945                 [AST_HTTP_POST] = ast_ari_channels_snoop_channel_cb,
1946         },
1947         .num_children = 0,
1948         .children = {  }
1949 };
1950 /*! \brief REST handler for /api-docs/channels.{format} */
1951 static struct stasis_rest_handlers channels_channelId = {
1952         .path_segment = "channelId",
1953         .is_wildcard = 1,
1954         .callbacks = {
1955                 [AST_HTTP_GET] = ast_ari_channels_get_cb,
1956                 [AST_HTTP_DELETE] = ast_ari_channels_hangup_cb,
1957         },
1958         .num_children = 12,
1959         .children = { &channels_channelId_continue,&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, }
1960 };
1961 /*! \brief REST handler for /api-docs/channels.{format} */
1962 static struct stasis_rest_handlers channels = {
1963         .path_segment = "channels",
1964         .callbacks = {
1965                 [AST_HTTP_GET] = ast_ari_channels_list_cb,
1966                 [AST_HTTP_POST] = ast_ari_channels_originate_cb,
1967         },
1968         .num_children = 1,
1969         .children = { &channels_channelId, }
1970 };
1971
1972 static int load_module(void)
1973 {
1974         int res = 0;
1975         stasis_app_ref();
1976         res |= ast_ari_add_handler(&channels);
1977         return res;
1978 }
1979
1980 static int unload_module(void)
1981 {
1982         ast_ari_remove_handler(&channels);
1983         stasis_app_unref();
1984         return 0;
1985 }
1986
1987 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "RESTful API module - Channel resources",
1988         .load = load_module,
1989         .unload = unload_module,
1990         .nonoptreq = "res_ari,res_stasis",
1991         );