ari: Add silence generator controls
[asterisk/asterisk.git] / res / ari / resource_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 /*! \file
20  *
21  * \brief Implementation for ARI stubs.
22  *
23  * \author David M. Lee, II <dlee@digium.com>
24  */
25
26 /*** MODULEINFO
27         <depend type="module">res_stasis_app_playback</depend>
28         <support_level>core</support_level>
29  ***/
30
31 #include "asterisk.h"
32
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34
35 #include "asterisk/file.h"
36 #include "asterisk/pbx.h"
37 #include "asterisk/bridge.h"
38 #include "asterisk/callerid.h"
39 #include "asterisk/stasis_app.h"
40 #include "asterisk/stasis_app_playback.h"
41 #include "asterisk/stasis_app_recording.h"
42 #include "asterisk/stasis_channels.h"
43 #include "asterisk/causes.h"
44 #include "resource_channels.h"
45
46 #include <limits.h>
47
48 /*!
49  * \brief Finds the control object for a channel, filling the response with an
50  * error, if appropriate.
51  * \param[out] response Response to fill with an error if control is not found.
52  * \param channel_id ID of the channel to lookup.
53  * \return Channel control object.
54  * \return \c NULL if control object does not exist.
55  */
56 static struct stasis_app_control *find_control(
57         struct ast_ari_response *response,
58         const char *channel_id)
59 {
60         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
61
62         ast_assert(response != NULL);
63
64         control = stasis_app_control_find_by_channel_id(channel_id);
65         if (control == NULL) {
66                 /* Distinguish between 404 and 409 errors */
67                 RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
68                 chan = ast_channel_get_by_name(channel_id);
69                 if (chan == NULL) {
70                         ast_ari_response_error(response, 404, "Not Found",
71                                    "Channel not found");
72                         return NULL;
73                 }
74
75                 ast_ari_response_error(response, 409, "Conflict",
76                            "Channel not in Stasis application");
77                 return NULL;
78         }
79
80         ao2_ref(control, +1);
81         return control;
82 }
83
84 void ast_ari_channels_continue_in_dialplan(
85         struct ast_variable *headers,
86         struct ast_ari_channels_continue_in_dialplan_args *args,
87         struct ast_ari_response *response)
88 {
89         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
90
91         ast_assert(response != NULL);
92
93         control = find_control(response, args->channel_id);
94         if (control == NULL) {
95                 return;
96         }
97
98         if (stasis_app_control_continue(control, args->context, args->extension, args->priority)) {
99                 ast_ari_response_alloc_failed(response);
100                 return;
101         }
102
103         ast_ari_response_no_content(response);
104 }
105
106 void ast_ari_channels_answer(struct ast_variable *headers,
107         struct ast_ari_channels_answer_args *args,
108         struct ast_ari_response *response)
109 {
110         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
111
112         control = find_control(response, args->channel_id);
113         if (control == NULL) {
114                 return;
115         }
116
117         if (stasis_app_control_answer(control) != 0) {
118                 ast_ari_response_error(
119                         response, 500, "Internal Server Error",
120                         "Failed to answer channel");
121                 return;
122         }
123
124         ast_ari_response_no_content(response);
125 }
126
127 void ast_ari_channels_ring(struct ast_variable *headers,
128         struct ast_ari_channels_ring_args *args,
129         struct ast_ari_response *response)
130 {
131         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
132
133         control = find_control(response, args->channel_id);
134         if (control == NULL) {
135                 return;
136         }
137
138         stasis_app_control_ring(control);
139
140         ast_ari_response_no_content(response);
141 }
142
143 void ast_ari_channels_ring_stop(struct ast_variable *headers,
144         struct ast_ari_channels_ring_stop_args *args,
145         struct ast_ari_response *response)
146 {
147         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
148
149         control = find_control(response, args->channel_id);
150         if (control == NULL) {
151                 return;
152         }
153
154         stasis_app_control_ring_stop(control);
155
156         ast_ari_response_no_content(response);
157 }
158
159 void ast_ari_channels_mute(struct ast_variable *headers,
160         struct ast_ari_channels_mute_args *args,
161         struct ast_ari_response *response)
162 {
163         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
164         unsigned int direction = 0;
165         enum ast_frame_type frametype = AST_FRAME_VOICE;
166
167         control = find_control(response, args->channel_id);
168         if (control == NULL) {
169                 return;
170         }
171
172         if (ast_strlen_zero(args->direction)) {
173                 ast_ari_response_error(
174                         response, 400, "Bad Request",
175                         "Direction is required");
176                 return;
177         }
178
179         if (!strcmp(args->direction, "in")) {
180                 direction = AST_MUTE_DIRECTION_READ;
181         } else if (!strcmp(args->direction, "out")) {
182                 direction = AST_MUTE_DIRECTION_WRITE;
183         } else if (!strcmp(args->direction, "both")) {
184                 direction = AST_MUTE_DIRECTION_READ | AST_MUTE_DIRECTION_WRITE;
185         } else {
186                 ast_ari_response_error(
187                         response, 400, "Bad Request",
188                         "Invalid direction specified");
189                 return;
190         }
191
192         stasis_app_control_mute(control, direction, frametype);
193
194         ast_ari_response_no_content(response);
195 }
196
197 void ast_ari_channels_unmute(struct ast_variable *headers,
198         struct ast_ari_channels_unmute_args *args,
199         struct ast_ari_response *response)
200 {
201         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
202         unsigned int direction = 0;
203         enum ast_frame_type frametype = AST_FRAME_VOICE;
204
205         control = find_control(response, args->channel_id);
206         if (control == NULL) {
207                 return;
208         }
209
210         if (ast_strlen_zero(args->direction)) {
211                 ast_ari_response_error(
212                         response, 400, "Bad Request",
213                         "Direction is required");
214                 return;
215         }
216
217         if (!strcmp(args->direction, "in")) {
218                 direction = AST_MUTE_DIRECTION_READ;
219         } else if (!strcmp(args->direction, "out")) {
220                 direction = AST_MUTE_DIRECTION_WRITE;
221         } else if (!strcmp(args->direction, "both")) {
222                 direction = AST_MUTE_DIRECTION_READ | AST_MUTE_DIRECTION_WRITE;
223         } else {
224                 ast_ari_response_error(
225                         response, 400, "Bad Request",
226                         "Invalid direction specified");
227                 return;
228         }
229
230         stasis_app_control_unmute(control, direction, frametype);
231
232         ast_ari_response_no_content(response);
233 }
234
235 void ast_ari_channels_send_dtmf(struct ast_variable *headers,
236         struct ast_ari_channels_send_dtmf_args *args,
237         struct ast_ari_response *response)
238 {
239         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
240
241         control = find_control(response, args->channel_id);
242         if (control == NULL) {
243                 return;
244         }
245
246         if (ast_strlen_zero(args->dtmf)) {
247                 ast_ari_response_error(
248                         response, 400, "Bad Request",
249                         "DTMF is required");
250                 return;
251         }
252
253         stasis_app_control_dtmf(control, args->dtmf, args->before, args->between, args->duration, args->after);
254
255         ast_ari_response_no_content(response);
256 }
257
258 void ast_ari_channels_hold(struct ast_variable *headers,
259         struct ast_ari_channels_hold_args *args,
260         struct ast_ari_response *response)
261 {
262         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
263
264         control = find_control(response, args->channel_id);
265         if (control == NULL) {
266                 /* Response filled in by find_control */
267                 return;
268         }
269
270         stasis_app_control_hold(control);
271
272         ast_ari_response_no_content(response);
273 }
274
275 void ast_ari_channels_unhold(struct ast_variable *headers,
276         struct ast_ari_channels_unhold_args *args,
277         struct ast_ari_response *response)
278 {
279         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
280
281         control = find_control(response, args->channel_id);
282         if (control == NULL) {
283                 /* Response filled in by find_control */
284                 return;
285         }
286
287         stasis_app_control_unhold(control);
288
289         ast_ari_response_no_content(response);
290 }
291
292 void ast_ari_channels_start_moh(struct ast_variable *headers,
293         struct ast_ari_channels_start_moh_args *args,
294         struct ast_ari_response *response)
295 {
296         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
297
298         control = find_control(response, args->channel_id);
299         if (control == NULL) {
300                 /* Response filled in by find_control */
301                 return;
302         }
303
304         stasis_app_control_moh_start(control, args->moh_class);
305         ast_ari_response_no_content(response);
306 }
307
308 void ast_ari_channels_stop_moh(struct ast_variable *headers,
309         struct ast_ari_channels_stop_moh_args *args,
310         struct ast_ari_response *response)
311 {
312         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
313
314         control = find_control(response, args->channel_id);
315         if (control == NULL) {
316                 /* Response filled in by find_control */
317                 return;
318         }
319
320         stasis_app_control_moh_stop(control);
321         ast_ari_response_no_content(response);
322 }
323
324 void ast_ari_channels_start_silence(struct ast_variable *headers,
325         struct ast_ari_channels_start_silence_args *args,
326         struct ast_ari_response *response)
327 {
328         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
329
330         control = find_control(response, args->channel_id);
331         if (control == NULL) {
332                 /* Response filled in by find_control */
333                 return;
334         }
335
336         stasis_app_control_silence_start(control);
337         ast_ari_response_no_content(response);
338 }
339
340 void ast_ari_channels_stop_silence(struct ast_variable *headers,
341         struct ast_ari_channels_stop_silence_args *args,
342         struct ast_ari_response *response)
343 {
344         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
345
346         control = find_control(response, args->channel_id);
347         if (control == NULL) {
348                 /* Response filled in by find_control */
349                 return;
350         }
351
352         stasis_app_control_silence_stop(control);
353         ast_ari_response_no_content(response);
354 }
355
356 void ast_ari_channels_play(struct ast_variable *headers,
357         struct ast_ari_channels_play_args *args,
358         struct ast_ari_response *response)
359 {
360         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
361         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
362         RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
363         RAII_VAR(char *, playback_url, NULL, ast_free);
364         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
365         const char *language;
366
367         ast_assert(response != NULL);
368
369         control = find_control(response, args->channel_id);
370         if (control == NULL) {
371                 /* Response filled in by find_control */
372                 return;
373         }
374
375         snapshot = stasis_app_control_get_snapshot(control);
376         if (!snapshot) {
377                 ast_ari_response_error(
378                         response, 404, "Not Found",
379                         "Channel not found");
380                 return;
381         }
382
383         if (args->skipms < 0) {
384                 ast_ari_response_error(
385                         response, 400, "Bad Request",
386                         "skipms cannot be negative");
387                 return;
388         }
389
390         if (args->offsetms < 0) {
391                 ast_ari_response_error(
392                         response, 400, "Bad Request",
393                         "offsetms cannot be negative");
394                 return;
395         }
396
397         language = S_OR(args->lang, snapshot->language);
398
399         playback = stasis_app_control_play_uri(control, args->media, language,
400                 args->channel_id, STASIS_PLAYBACK_TARGET_CHANNEL, args->skipms, args->offsetms);
401         if (!playback) {
402                 ast_ari_response_error(
403                         response, 500, "Internal Server Error",
404                         "Failed to queue media for playback");
405                 return;
406         }
407
408         ast_asprintf(&playback_url, "/playback/%s",
409                 stasis_app_playback_get_id(playback));
410         if (!playback_url) {
411                 ast_ari_response_error(
412                         response, 500, "Internal Server Error",
413                         "Out of memory");
414                 return;
415         }
416
417         json = stasis_app_playback_to_json(playback);
418         if (!json) {
419                 ast_ari_response_error(
420                         response, 500, "Internal Server Error",
421                         "Out of memory");
422                 return;
423         }
424
425         ast_ari_response_created(response, playback_url, json);
426 }
427
428 void ast_ari_channels_record(struct ast_variable *headers,
429         struct ast_ari_channels_record_args *args,
430         struct ast_ari_response *response)
431 {
432         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
433         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
434         RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
435         RAII_VAR(char *, recording_url, NULL, ast_free);
436         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
437         RAII_VAR(struct stasis_app_recording_options *, options, NULL,
438                 ao2_cleanup);
439         RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
440         size_t uri_name_maxlen;
441
442         ast_assert(response != NULL);
443
444         if (args->max_duration_seconds < 0) {
445                 ast_ari_response_error(
446                         response, 400, "Bad Request",
447                         "max_duration_seconds cannot be negative");
448                 return;
449         }
450
451         if (args->max_silence_seconds < 0) {
452                 ast_ari_response_error(
453                         response, 400, "Bad Request",
454                         "max_silence_seconds cannot be negative");
455                 return;
456         }
457
458         control = find_control(response, args->channel_id);
459         if (control == NULL) {
460                 /* Response filled in by find_control */
461                 return;
462         }
463
464         options = stasis_app_recording_options_create(args->name, args->format);
465         if (options == NULL) {
466                 ast_ari_response_error(
467                         response, 500, "Internal Server Error",
468                         "Out of memory");
469         }
470         options->max_silence_seconds = args->max_silence_seconds;
471         options->max_duration_seconds = args->max_duration_seconds;
472         options->terminate_on =
473                 stasis_app_recording_termination_parse(args->terminate_on);
474         options->if_exists =
475                 stasis_app_recording_if_exists_parse(args->if_exists);
476         options->beep = args->beep;
477
478         if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
479                 ast_ari_response_error(
480                         response, 400, "Bad Request",
481                         "terminateOn invalid");
482                 return;
483         }
484
485         if (options->if_exists == -1) {
486                 ast_ari_response_error(
487                         response, 400, "Bad Request",
488                         "ifExists invalid");
489                 return;
490         }
491
492         if (!ast_get_format_for_file_ext(options->format)) {
493                 ast_ari_response_error(
494                         response, 422, "Unprocessable Entity",
495                         "specified format is unknown on this system");
496                 return;
497         }
498
499         recording = stasis_app_control_record(control, options);
500         if (recording == NULL) {
501                 switch(errno) {
502                 case EINVAL:
503                         /* While the arguments are invalid, we should have
504                          * caught them prior to calling record.
505                          */
506                         ast_ari_response_error(
507                                 response, 500, "Internal Server Error",
508                                 "Error parsing request");
509                         break;
510                 case EEXIST:
511                         ast_ari_response_error(response, 409, "Conflict",
512                                 "Recording '%s' already exists and can not be overwritten",
513                                 args->name);
514                         break;
515                 case ENOMEM:
516                         ast_ari_response_error(
517                                 response, 500, "Internal Server Error",
518                                 "Out of memory");
519                         break;
520                 case EPERM:
521                         ast_ari_response_error(
522                                 response, 400, "Bad Request",
523                                 "Recording name invalid");
524                         break;
525                 default:
526                         ast_log(LOG_WARNING,
527                                 "Unrecognized recording error: %s\n",
528                                 strerror(errno));
529                         ast_ari_response_error(
530                                 response, 500, "Internal Server Error",
531                                 "Internal Server Error");
532                         break;
533                 }
534                 return;
535         }
536
537         uri_name_maxlen = strlen(args->name) * 3;
538         uri_encoded_name = ast_malloc(uri_name_maxlen);
539         if (!uri_encoded_name) {
540                 ast_ari_response_error(
541                         response, 500, "Internal Server Error",
542                         "Out of memory");
543                 return;
544         }
545         ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen,
546                 ast_uri_http);
547
548         ast_asprintf(&recording_url, "/recordings/live/%s", uri_encoded_name);
549         if (!recording_url) {
550                 ast_ari_response_error(
551                         response, 500, "Internal Server Error",
552                         "Out of memory");
553                 return;
554         }
555
556         json = stasis_app_recording_to_json(recording);
557         if (!json) {
558                 ast_ari_response_error(
559                         response, 500, "Internal Server Error",
560                         "Out of memory");
561                 return;
562         }
563
564         ast_ari_response_created(response, recording_url, json);
565 }
566
567 void ast_ari_channels_get(struct ast_variable *headers,
568         struct ast_ari_channels_get_args *args,
569         struct ast_ari_response *response)
570 {
571         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
572         struct stasis_cache *cache;
573         struct ast_channel_snapshot *snapshot;
574
575         cache = ast_channel_cache();
576         if (!cache) {
577                 ast_ari_response_error(
578                         response, 500, "Internal Server Error",
579                         "Message bus not initialized");
580                 return;
581         }
582
583         msg = stasis_cache_get(cache, ast_channel_snapshot_type(),
584                                args->channel_id);
585         if (!msg) {
586                 ast_ari_response_error(
587                         response, 404, "Not Found",
588                         "Channel not found");
589                 return;
590         }
591
592         snapshot = stasis_message_data(msg);
593         ast_assert(snapshot != NULL);
594
595         ast_ari_response_ok(response,
596                                 ast_channel_snapshot_to_json(snapshot));
597 }
598
599 void ast_ari_channels_hangup(struct ast_variable *headers,
600         struct ast_ari_channels_hangup_args *args,
601         struct ast_ari_response *response)
602 {
603         RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
604         int cause;
605
606         chan = ast_channel_get_by_name(args->channel_id);
607         if (chan == NULL) {
608                 ast_ari_response_error(
609                         response, 404, "Not Found",
610                         "Channel not found");
611                 return;
612         }
613
614         if (ast_strlen_zero(args->reason) || !strcmp(args->reason, "normal")) {
615                 cause = AST_CAUSE_NORMAL;
616         } else if (!strcmp(args->reason, "busy")) {
617                 cause = AST_CAUSE_BUSY;
618         } else if (!strcmp(args->reason, "congestion")) {
619                 cause = AST_CAUSE_CONGESTION;
620         } else {
621                 ast_ari_response_error(
622                         response, 400, "Invalid Reason",
623                         "Invalid reason for hangup provided");
624                 return;
625         }
626
627         ast_channel_hangupcause_set(chan, cause);
628         ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
629
630         ast_ari_response_no_content(response);
631 }
632
633 void ast_ari_channels_list(struct ast_variable *headers,
634         struct ast_ari_channels_list_args *args,
635         struct ast_ari_response *response)
636 {
637         RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
638         RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
639         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
640         struct ao2_iterator i;
641         void *obj;
642
643         cache = ast_channel_cache();
644         if (!cache) {
645                 ast_ari_response_error(
646                         response, 500, "Internal Server Error",
647                         "Message bus not initialized");
648                 return;
649         }
650         ao2_ref(cache, +1);
651
652         snapshots = stasis_cache_dump(cache, ast_channel_snapshot_type());
653         if (!snapshots) {
654                 ast_ari_response_alloc_failed(response);
655                 return;
656         }
657
658         json = ast_json_array_create();
659         if (!json) {
660                 ast_ari_response_alloc_failed(response);
661                 return;
662         }
663
664         i = ao2_iterator_init(snapshots, 0);
665         while ((obj = ao2_iterator_next(&i))) {
666                 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
667                 struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
668                 int r = ast_json_array_append(
669                         json, ast_channel_snapshot_to_json(snapshot));
670                 if (r != 0) {
671                         ast_ari_response_alloc_failed(response);
672                         return;
673                 }
674         }
675         ao2_iterator_destroy(&i);
676
677         ast_ari_response_ok(response, ast_json_ref(json));
678 }
679
680 void ast_ari_channels_originate(struct ast_variable *headers,
681         struct ast_ari_channels_originate_args *args,
682         struct ast_ari_response *response)
683 {
684         char *dialtech;
685         char dialdevice[AST_CHANNEL_NAME];
686         char *caller_id = NULL;
687         char *cid_num = NULL;
688         char *cid_name = NULL;
689         int timeout = 30000;
690
691         char *stuff;
692         struct ast_channel *chan;
693         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
694
695         if (ast_strlen_zero(args->endpoint)) {
696                 ast_ari_response_error(response, 400, "Bad Request",
697                         "Endpoint must be specified");
698                 return;
699         }
700
701         dialtech = ast_strdupa(args->endpoint);
702         if ((stuff = strchr(dialtech, '/'))) {
703                 *stuff++ = '\0';
704                 ast_copy_string(dialdevice, stuff, sizeof(dialdevice));
705         }
706
707         if (ast_strlen_zero(dialtech) || ast_strlen_zero(dialdevice)) {
708                 ast_ari_response_error(response, 400, "Bad Request",
709                         "Invalid endpoint specified");
710                 return;
711         }
712
713         if (args->timeout > 0) {
714                 timeout = args->timeout * 1000;
715         } else if (args->timeout == -1) {
716                 timeout = -1;
717         }
718
719         if (!ast_strlen_zero(args->caller_id)) {
720                 caller_id = ast_strdupa(args->caller_id);
721                 ast_callerid_parse(caller_id, &cid_name, &cid_num);
722
723                 if (ast_is_shrinkable_phonenumber(cid_num)) {
724                         ast_shrink_phone_number(cid_num);
725                 }
726         }
727
728         if (!ast_strlen_zero(args->app)) {
729                 const char *app = "Stasis";
730
731                 RAII_VAR(struct ast_str *, appdata, ast_str_create(64), ast_free);
732
733                 if (!appdata) {
734                         ast_ari_response_alloc_failed(response);
735                         return;
736                 }
737
738                 ast_str_set(&appdata, 0, "%s", args->app);
739                 if (!ast_strlen_zero(args->app_args)) {
740                         ast_str_append(&appdata, 0, ",%s", args->app_args);
741                 }
742
743                 /* originate a channel, putting it into an application */
744                 if (ast_pbx_outgoing_app(dialtech, NULL, dialdevice, timeout, app, ast_str_buffer(appdata), NULL, 0, cid_num, cid_name, NULL, NULL, &chan)) {
745                         ast_ari_response_alloc_failed(response);
746                         return;
747                 }
748         } else if (!ast_strlen_zero(args->extension)) {
749                 /* originate a channel, sending it to an extension */
750                 if (ast_pbx_outgoing_exten(dialtech, NULL, dialdevice, timeout, S_OR(args->context, "default"), args->extension, args->priority ? args->priority : 1, NULL, 0, cid_num, cid_name, NULL, NULL, &chan, 0)) {
751                         ast_ari_response_alloc_failed(response);
752                         return;
753                 }
754         } else {
755                 ast_ari_response_error(response, 400, "Bad Request",
756                         "Application or extension must be specified");
757                 return;
758         }
759
760         snapshot = ast_channel_snapshot_create(chan);
761         ast_channel_unlock(chan);
762
763         if (!ast_strlen_zero(args->app)) {
764                 /* channel: + channel ID + null terminator */
765                 char uri[9 + strlen(ast_channel_uniqueid(chan))];
766                 const char *uris[1] = { uri, };
767
768                 sprintf(uri, "channel:%s", ast_channel_uniqueid(chan));
769                 stasis_app_subscribe(args->app, uris, 1, NULL);
770         }
771
772         ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot));
773         ast_channel_unref(chan);
774 }
775
776 void ast_ari_channels_get_channel_var(struct ast_variable *headers,
777         struct ast_ari_channels_get_channel_var_args *args,
778         struct ast_ari_response *response)
779 {
780         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
781         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
782         RAII_VAR(char *, value, NULL, ast_free);
783
784         ast_assert(response != NULL);
785
786         if (ast_strlen_zero(args->variable)) {
787                 ast_ari_response_error(
788                         response, 400, "Bad Request",
789                         "Variable name is required");
790                 return;
791         }
792
793         control = find_control(response, args->channel_id);
794         if (control == NULL) {
795                 /* response filled in by find_control */
796                 return;
797         }
798
799         value = stasis_app_control_get_channel_var(control, args->variable);
800
801         if (!(json = ast_json_pack("{s: s}", "value", S_OR(value, "")))) {
802                 ast_ari_response_alloc_failed(response);
803                 return;
804         }
805
806         ast_ari_response_ok(response, ast_json_ref(json));
807 }
808
809 void ast_ari_channels_set_channel_var(struct ast_variable *headers,
810         struct ast_ari_channels_set_channel_var_args *args,
811         struct ast_ari_response *response)
812 {
813         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
814
815         ast_assert(response != NULL);
816
817         if (ast_strlen_zero(args->variable)) {
818                 ast_ari_response_error(
819                         response, 400, "Bad Request",
820                         "Variable name is required");
821                 return;
822         }
823
824         control = find_control(response, args->channel_id);
825         if (control == NULL) {
826                 /* response filled in by find_control */
827                 return;
828         }
829
830         if (stasis_app_control_set_channel_var(control, args->variable, args->value)) {
831                 ast_ari_response_error(
832                         response, 400, "Bad Request",
833                         "Failed to execute function");
834                 return;
835         }
836
837         ast_ari_response_no_content(response);
838 }
839