media formats: re-architect handling of media for performance improvements
[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_app_snoop.h"
43 #include "asterisk/stasis_channels.h"
44 #include "asterisk/causes.h"
45 #include "asterisk/format_cache.h"
46 #include "asterisk/core_local.h"
47 #include "resource_channels.h"
48
49 #include <limits.h>
50
51 /*!
52  * \brief Finds the control object for a channel, filling the response with an
53  * error, if appropriate.
54  * \param[out] response Response to fill with an error if control is not found.
55  * \param channel_id ID of the channel to lookup.
56  * \return Channel control object.
57  * \return \c NULL if control object does not exist.
58  */
59 static struct stasis_app_control *find_control(
60         struct ast_ari_response *response,
61         const char *channel_id)
62 {
63         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
64
65         ast_assert(response != NULL);
66
67         control = stasis_app_control_find_by_channel_id(channel_id);
68         if (control == NULL) {
69                 /* Distinguish between 404 and 409 errors */
70                 RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
71                 chan = ast_channel_get_by_name(channel_id);
72                 if (chan == NULL) {
73                         ast_ari_response_error(response, 404, "Not Found",
74                                    "Channel not found");
75                         return NULL;
76                 }
77
78                 ast_ari_response_error(response, 409, "Conflict",
79                            "Channel not in Stasis application");
80                 return NULL;
81         }
82
83         ao2_ref(control, +1);
84         return control;
85 }
86
87 void ast_ari_channels_continue_in_dialplan(
88         struct ast_variable *headers,
89         struct ast_ari_channels_continue_in_dialplan_args *args,
90         struct ast_ari_response *response)
91 {
92         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
93
94         ast_assert(response != NULL);
95
96         control = find_control(response, args->channel_id);
97         if (control == NULL) {
98                 return;
99         }
100
101         if (stasis_app_control_continue(control, args->context, args->extension, args->priority)) {
102                 ast_ari_response_alloc_failed(response);
103                 return;
104         }
105
106         ast_ari_response_no_content(response);
107 }
108
109 void ast_ari_channels_answer(struct ast_variable *headers,
110         struct ast_ari_channels_answer_args *args,
111         struct ast_ari_response *response)
112 {
113         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
114
115         control = find_control(response, args->channel_id);
116         if (control == NULL) {
117                 return;
118         }
119
120         if (stasis_app_control_answer(control) != 0) {
121                 ast_ari_response_error(
122                         response, 500, "Internal Server Error",
123                         "Failed to answer channel");
124                 return;
125         }
126
127         ast_ari_response_no_content(response);
128 }
129
130 void ast_ari_channels_ring(struct ast_variable *headers,
131         struct ast_ari_channels_ring_args *args,
132         struct ast_ari_response *response)
133 {
134         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
135
136         control = find_control(response, args->channel_id);
137         if (control == NULL) {
138                 return;
139         }
140
141         stasis_app_control_ring(control);
142
143         ast_ari_response_no_content(response);
144 }
145
146 void ast_ari_channels_ring_stop(struct ast_variable *headers,
147         struct ast_ari_channels_ring_stop_args *args,
148         struct ast_ari_response *response)
149 {
150         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
151
152         control = find_control(response, args->channel_id);
153         if (control == NULL) {
154                 return;
155         }
156
157         stasis_app_control_ring_stop(control);
158
159         ast_ari_response_no_content(response);
160 }
161
162 void ast_ari_channels_mute(struct ast_variable *headers,
163         struct ast_ari_channels_mute_args *args,
164         struct ast_ari_response *response)
165 {
166         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
167         unsigned int direction = 0;
168         enum ast_frame_type frametype = AST_FRAME_VOICE;
169
170         control = find_control(response, args->channel_id);
171         if (control == NULL) {
172                 return;
173         }
174
175         if (ast_strlen_zero(args->direction)) {
176                 ast_ari_response_error(
177                         response, 400, "Bad Request",
178                         "Direction is required");
179                 return;
180         }
181
182         if (!strcmp(args->direction, "in")) {
183                 direction = AST_MUTE_DIRECTION_READ;
184         } else if (!strcmp(args->direction, "out")) {
185                 direction = AST_MUTE_DIRECTION_WRITE;
186         } else if (!strcmp(args->direction, "both")) {
187                 direction = AST_MUTE_DIRECTION_READ | AST_MUTE_DIRECTION_WRITE;
188         } else {
189                 ast_ari_response_error(
190                         response, 400, "Bad Request",
191                         "Invalid direction specified");
192                 return;
193         }
194
195         stasis_app_control_mute(control, direction, frametype);
196
197         ast_ari_response_no_content(response);
198 }
199
200 void ast_ari_channels_unmute(struct ast_variable *headers,
201         struct ast_ari_channels_unmute_args *args,
202         struct ast_ari_response *response)
203 {
204         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
205         unsigned int direction = 0;
206         enum ast_frame_type frametype = AST_FRAME_VOICE;
207
208         control = find_control(response, args->channel_id);
209         if (control == NULL) {
210                 return;
211         }
212
213         if (ast_strlen_zero(args->direction)) {
214                 ast_ari_response_error(
215                         response, 400, "Bad Request",
216                         "Direction is required");
217                 return;
218         }
219
220         if (!strcmp(args->direction, "in")) {
221                 direction = AST_MUTE_DIRECTION_READ;
222         } else if (!strcmp(args->direction, "out")) {
223                 direction = AST_MUTE_DIRECTION_WRITE;
224         } else if (!strcmp(args->direction, "both")) {
225                 direction = AST_MUTE_DIRECTION_READ | AST_MUTE_DIRECTION_WRITE;
226         } else {
227                 ast_ari_response_error(
228                         response, 400, "Bad Request",
229                         "Invalid direction specified");
230                 return;
231         }
232
233         stasis_app_control_unmute(control, direction, frametype);
234
235         ast_ari_response_no_content(response);
236 }
237
238 void ast_ari_channels_send_dtmf(struct ast_variable *headers,
239         struct ast_ari_channels_send_dtmf_args *args,
240         struct ast_ari_response *response)
241 {
242         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
243
244         control = find_control(response, args->channel_id);
245         if (control == NULL) {
246                 return;
247         }
248
249         if (ast_strlen_zero(args->dtmf)) {
250                 ast_ari_response_error(
251                         response, 400, "Bad Request",
252                         "DTMF is required");
253                 return;
254         }
255
256         stasis_app_control_dtmf(control, args->dtmf, args->before, args->between, args->duration, args->after);
257
258         ast_ari_response_no_content(response);
259 }
260
261 void ast_ari_channels_hold(struct ast_variable *headers,
262         struct ast_ari_channels_hold_args *args,
263         struct ast_ari_response *response)
264 {
265         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
266
267         control = find_control(response, args->channel_id);
268         if (control == NULL) {
269                 /* Response filled in by find_control */
270                 return;
271         }
272
273         stasis_app_control_hold(control);
274
275         ast_ari_response_no_content(response);
276 }
277
278 void ast_ari_channels_unhold(struct ast_variable *headers,
279         struct ast_ari_channels_unhold_args *args,
280         struct ast_ari_response *response)
281 {
282         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
283
284         control = find_control(response, args->channel_id);
285         if (control == NULL) {
286                 /* Response filled in by find_control */
287                 return;
288         }
289
290         stasis_app_control_unhold(control);
291
292         ast_ari_response_no_content(response);
293 }
294
295 void ast_ari_channels_start_moh(struct ast_variable *headers,
296         struct ast_ari_channels_start_moh_args *args,
297         struct ast_ari_response *response)
298 {
299         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
300
301         control = find_control(response, args->channel_id);
302         if (control == NULL) {
303                 /* Response filled in by find_control */
304                 return;
305         }
306
307         stasis_app_control_moh_start(control, args->moh_class);
308         ast_ari_response_no_content(response);
309 }
310
311 void ast_ari_channels_stop_moh(struct ast_variable *headers,
312         struct ast_ari_channels_stop_moh_args *args,
313         struct ast_ari_response *response)
314 {
315         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
316
317         control = find_control(response, args->channel_id);
318         if (control == NULL) {
319                 /* Response filled in by find_control */
320                 return;
321         }
322
323         stasis_app_control_moh_stop(control);
324         ast_ari_response_no_content(response);
325 }
326
327 void ast_ari_channels_start_silence(struct ast_variable *headers,
328         struct ast_ari_channels_start_silence_args *args,
329         struct ast_ari_response *response)
330 {
331         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
332
333         control = find_control(response, args->channel_id);
334         if (control == NULL) {
335                 /* Response filled in by find_control */
336                 return;
337         }
338
339         stasis_app_control_silence_start(control);
340         ast_ari_response_no_content(response);
341 }
342
343 void ast_ari_channels_stop_silence(struct ast_variable *headers,
344         struct ast_ari_channels_stop_silence_args *args,
345         struct ast_ari_response *response)
346 {
347         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
348
349         control = find_control(response, args->channel_id);
350         if (control == NULL) {
351                 /* Response filled in by find_control */
352                 return;
353         }
354
355         stasis_app_control_silence_stop(control);
356         ast_ari_response_no_content(response);
357 }
358
359 static void ari_channels_handle_play(
360         const char *args_channel_id,
361         const char *args_media,
362         const char *args_lang,
363         int args_offsetms,
364         int args_skipms,
365         const char *args_playback_id,
366         struct ast_ari_response *response)
367 {
368         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
369         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
370         RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
371         RAII_VAR(char *, playback_url, NULL, ast_free);
372         struct ast_json *json;
373         const char *language;
374
375         ast_assert(response != NULL);
376
377         control = find_control(response, args_channel_id);
378         if (control == NULL) {
379                 /* Response filled in by find_control */
380                 return;
381         }
382
383         snapshot = stasis_app_control_get_snapshot(control);
384         if (!snapshot) {
385                 ast_ari_response_error(
386                         response, 404, "Not Found",
387                         "Channel not found");
388                 return;
389         }
390
391         if (args_skipms < 0) {
392                 ast_ari_response_error(
393                         response, 400, "Bad Request",
394                         "skipms cannot be negative");
395                 return;
396         }
397
398         if (args_offsetms < 0) {
399                 ast_ari_response_error(
400                         response, 400, "Bad Request",
401                         "offsetms cannot be negative");
402                 return;
403         }
404
405         language = S_OR(args_lang, snapshot->language);
406
407         playback = stasis_app_control_play_uri(control, args_media, language,
408                 args_channel_id, STASIS_PLAYBACK_TARGET_CHANNEL, args_skipms, args_offsetms, args_playback_id);
409         if (!playback) {
410                 ast_ari_response_error(
411                         response, 500, "Internal Server Error",
412                         "Failed to queue media for playback");
413                 return;
414         }
415
416         if (ast_asprintf(&playback_url, "/playback/%s",
417                         stasis_app_playback_get_id(playback)) == -1) {
418                 playback_url = NULL;
419                 ast_ari_response_error(
420                         response, 500, "Internal Server Error",
421                         "Out of memory");
422                 return;
423         }
424
425         json = stasis_app_playback_to_json(playback);
426         if (!json) {
427                 ast_ari_response_error(
428                         response, 500, "Internal Server Error",
429                         "Out of memory");
430                 return;
431         }
432
433         ast_ari_response_created(response, playback_url, json);
434 }
435
436 void ast_ari_channels_play(struct ast_variable *headers,
437         struct ast_ari_channels_play_args *args,
438         struct ast_ari_response *response)
439 {
440         ari_channels_handle_play(
441                 args->channel_id,
442                 args->media,
443                 args->lang,
444                 args->offsetms,
445                 args->skipms,
446                 args->playback_id,
447                 response);
448 }
449
450 void ast_ari_channels_play_with_id(struct ast_variable *headers,
451         struct ast_ari_channels_play_with_id_args *args,
452         struct ast_ari_response *response)
453 {
454         ari_channels_handle_play(
455                 args->channel_id,
456                 args->media,
457                 args->lang,
458                 args->offsetms,
459                 args->skipms,
460                 args->playback_id,
461                 response);
462 }
463
464 void ast_ari_channels_record(struct ast_variable *headers,
465         struct ast_ari_channels_record_args *args,
466         struct ast_ari_response *response)
467 {
468         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
469         RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
470         RAII_VAR(char *, recording_url, NULL, ast_free);
471         struct ast_json *json;
472         RAII_VAR(struct stasis_app_recording_options *, options, NULL,
473                 ao2_cleanup);
474         RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
475         size_t uri_name_maxlen;
476
477         ast_assert(response != NULL);
478
479         if (args->max_duration_seconds < 0) {
480                 ast_ari_response_error(
481                         response, 400, "Bad Request",
482                         "max_duration_seconds cannot be negative");
483                 return;
484         }
485
486         if (args->max_silence_seconds < 0) {
487                 ast_ari_response_error(
488                         response, 400, "Bad Request",
489                         "max_silence_seconds cannot be negative");
490                 return;
491         }
492
493         control = find_control(response, args->channel_id);
494         if (control == NULL) {
495                 /* Response filled in by find_control */
496                 return;
497         }
498
499         options = stasis_app_recording_options_create(args->name, args->format);
500         if (options == NULL) {
501                 ast_ari_response_error(
502                         response, 500, "Internal Server Error",
503                         "Out of memory");
504         }
505         ast_string_field_build(options, target, "channel:%s", args->channel_id);
506         options->max_silence_seconds = args->max_silence_seconds;
507         options->max_duration_seconds = args->max_duration_seconds;
508         options->terminate_on =
509                 stasis_app_recording_termination_parse(args->terminate_on);
510         options->if_exists =
511                 stasis_app_recording_if_exists_parse(args->if_exists);
512         options->beep = args->beep;
513
514         if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
515                 ast_ari_response_error(
516                         response, 400, "Bad Request",
517                         "terminateOn invalid");
518                 return;
519         }
520
521         if (options->if_exists == -1) {
522                 ast_ari_response_error(
523                         response, 400, "Bad Request",
524                         "ifExists invalid");
525                 return;
526         }
527
528         if (!ast_get_format_for_file_ext(options->format)) {
529                 ast_ari_response_error(
530                         response, 422, "Unprocessable Entity",
531                         "specified format is unknown on this system");
532                 return;
533         }
534
535         recording = stasis_app_control_record(control, options);
536         if (recording == NULL) {
537                 switch(errno) {
538                 case EINVAL:
539                         /* While the arguments are invalid, we should have
540                          * caught them prior to calling record.
541                          */
542                         ast_ari_response_error(
543                                 response, 500, "Internal Server Error",
544                                 "Error parsing request");
545                         break;
546                 case EEXIST:
547                         ast_ari_response_error(response, 409, "Conflict",
548                                 "Recording '%s' already exists and can not be overwritten",
549                                 args->name);
550                         break;
551                 case ENOMEM:
552                         ast_ari_response_error(
553                                 response, 500, "Internal Server Error",
554                                 "Out of memory");
555                         break;
556                 case EPERM:
557                         ast_ari_response_error(
558                                 response, 400, "Bad Request",
559                                 "Recording name invalid");
560                         break;
561                 default:
562                         ast_log(LOG_WARNING,
563                                 "Unrecognized recording error: %s\n",
564                                 strerror(errno));
565                         ast_ari_response_error(
566                                 response, 500, "Internal Server Error",
567                                 "Internal Server Error");
568                         break;
569                 }
570                 return;
571         }
572
573         uri_name_maxlen = strlen(args->name) * 3;
574         uri_encoded_name = ast_malloc(uri_name_maxlen);
575         if (!uri_encoded_name) {
576                 ast_ari_response_error(
577                         response, 500, "Internal Server Error",
578                         "Out of memory");
579                 return;
580         }
581         ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen,
582                 ast_uri_http);
583
584         if (ast_asprintf(&recording_url, "/recordings/live/%s",
585                         uri_encoded_name) == -1) {
586                 recording_url = NULL;
587                 ast_ari_response_error(
588                         response, 500, "Internal Server Error",
589                         "Out of memory");
590                 return;
591         }
592
593         json = stasis_app_recording_to_json(recording);
594         if (!json) {
595                 ast_ari_response_error(
596                         response, 500, "Internal Server Error",
597                         "Out of memory");
598                 return;
599         }
600
601         ast_ari_response_created(response, recording_url, json);
602 }
603
604 void ast_ari_channels_get(struct ast_variable *headers,
605         struct ast_ari_channels_get_args *args,
606         struct ast_ari_response *response)
607 {
608         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
609         struct stasis_cache *cache;
610         struct ast_channel_snapshot *snapshot;
611
612         cache = ast_channel_cache();
613         if (!cache) {
614                 ast_ari_response_error(
615                         response, 500, "Internal Server Error",
616                         "Message bus not initialized");
617                 return;
618         }
619
620         msg = stasis_cache_get(cache, ast_channel_snapshot_type(),
621                                    args->channel_id);
622         if (!msg) {
623                 ast_ari_response_error(
624                         response, 404, "Not Found",
625                         "Channel not found");
626                 return;
627         }
628
629         snapshot = stasis_message_data(msg);
630         ast_assert(snapshot != NULL);
631
632         ast_ari_response_ok(response,
633                                 ast_channel_snapshot_to_json(snapshot, NULL));
634 }
635
636 void ast_ari_channels_hangup(struct ast_variable *headers,
637         struct ast_ari_channels_hangup_args *args,
638         struct ast_ari_response *response)
639 {
640         RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
641         int cause;
642
643         chan = ast_channel_get_by_name(args->channel_id);
644         if (chan == NULL) {
645                 ast_ari_response_error(
646                         response, 404, "Not Found",
647                         "Channel not found");
648                 return;
649         }
650
651         if (ast_strlen_zero(args->reason) || !strcmp(args->reason, "normal")) {
652                 cause = AST_CAUSE_NORMAL;
653         } else if (!strcmp(args->reason, "busy")) {
654                 cause = AST_CAUSE_BUSY;
655         } else if (!strcmp(args->reason, "congestion")) {
656                 cause = AST_CAUSE_CONGESTION;
657         } else {
658                 ast_ari_response_error(
659                         response, 400, "Invalid Reason",
660                         "Invalid reason for hangup provided");
661                 return;
662         }
663
664         ast_channel_hangupcause_set(chan, cause);
665         ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
666
667         ast_ari_response_no_content(response);
668 }
669
670 void ast_ari_channels_list(struct ast_variable *headers,
671         struct ast_ari_channels_list_args *args,
672         struct ast_ari_response *response)
673 {
674         RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
675         RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
676         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
677         struct ao2_iterator i;
678         void *obj;
679         struct stasis_message_sanitizer *sanitize = stasis_app_get_sanitizer();
680
681         cache = ast_channel_cache();
682         if (!cache) {
683                 ast_ari_response_error(
684                         response, 500, "Internal Server Error",
685                         "Message bus not initialized");
686                 return;
687         }
688         ao2_ref(cache, +1);
689
690         snapshots = stasis_cache_dump(cache, ast_channel_snapshot_type());
691         if (!snapshots) {
692                 ast_ari_response_alloc_failed(response);
693                 return;
694         }
695
696         json = ast_json_array_create();
697         if (!json) {
698                 ast_ari_response_alloc_failed(response);
699                 return;
700         }
701
702         i = ao2_iterator_init(snapshots, 0);
703         while ((obj = ao2_iterator_next(&i))) {
704                 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
705                 struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
706                 int r;
707
708                 if (sanitize && sanitize->channel_snapshot
709                         && sanitize->channel_snapshot(snapshot)) {
710                         continue;
711                 }
712
713                 r = ast_json_array_append(
714                         json, ast_channel_snapshot_to_json(snapshot, NULL));
715                 if (r != 0) {
716                         ast_ari_response_alloc_failed(response);
717                         ao2_iterator_destroy(&i);
718                         return;
719                 }
720         }
721         ao2_iterator_destroy(&i);
722
723         ast_ari_response_ok(response, ast_json_ref(json));
724 }
725
726 static int json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables)
727 {
728         struct ast_variable *current = NULL;
729         struct ast_json_iter *it_json_var;
730
731         for (it_json_var = ast_json_object_iter(json_variables); it_json_var;
732                  it_json_var = ast_json_object_iter_next(json_variables, it_json_var)) {
733                 struct ast_variable *new_var;
734
735                 new_var = ast_variable_new(ast_json_object_iter_key(it_json_var),
736                                                                    ast_json_string_get(ast_json_object_iter_value(it_json_var)),
737                                                                    "");
738                 if (!new_var) {
739                         ast_variables_destroy(*variables);
740                         *variables = NULL;
741                         return 1;
742                 }
743
744                 if (!current) {
745                         *variables = new_var;
746                         current = *variables;
747                 } else {
748                         current->next = new_var;
749                         current = new_var;
750                 }
751         }
752
753         return 0;
754 }
755
756 static void ari_channels_handle_originate_with_id(const char *args_endpoint,
757         const char *args_extension,
758         const char *args_context,
759         long args_priority,
760         const char *args_app,
761         const char *args_app_args,
762         const char *args_caller_id,
763         int args_timeout,
764         struct ast_variable *variables,
765         const char *args_channel_id,
766         const char *args_other_channel_id,
767         struct ast_ari_response *response)
768 {
769         char *dialtech;
770         char dialdevice[AST_CHANNEL_NAME];
771         char *caller_id = NULL;
772         char *cid_num = NULL;
773         char *cid_name = NULL;
774         int timeout = 30000;
775         RAII_VAR(struct ast_format_cap *, cap,
776                 ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);
777         char *stuff;
778         struct ast_channel *chan;
779         struct ast_channel *local_peer;
780         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
781         struct ast_assigned_ids assignedids = {
782                 .uniqueid = args_channel_id,
783                 .uniqueid2 = args_other_channel_id,
784         };
785
786         if (!cap) {
787                 ast_ari_response_alloc_failed(response);
788                 return;
789         }
790         ast_format_cap_append(cap, ast_format_slin, 0);
791
792         if ((assignedids.uniqueid && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid))
793                 || (assignedids.uniqueid2 && AST_MAX_PUBLIC_UNIQUEID < strlen(assignedids.uniqueid2))) {
794                 ast_ari_response_error(response, 400, "Bad Request",
795                         "Uniqueid length exceeds maximum of %d", AST_MAX_PUBLIC_UNIQUEID);
796                 return;
797         }
798
799         if (ast_strlen_zero(args_endpoint)) {
800                 ast_ari_response_error(response, 400, "Bad Request",
801                         "Endpoint must be specified");
802                 return;
803         }
804
805         dialtech = ast_strdupa(args_endpoint);
806         if ((stuff = strchr(dialtech, '/'))) {
807                 *stuff++ = '\0';
808                 ast_copy_string(dialdevice, stuff, sizeof(dialdevice));
809         }
810
811         if (ast_strlen_zero(dialtech) || ast_strlen_zero(dialdevice)) {
812                 ast_ari_response_error(response, 400, "Bad Request",
813                         "Invalid endpoint specified");
814                 return;
815         }
816
817         if (args_timeout > 0) {
818                 timeout = args_timeout * 1000;
819         } else if (args_timeout == -1) {
820                 timeout = -1;
821         }
822
823         if (!ast_strlen_zero(args_caller_id)) {
824                 caller_id = ast_strdupa(args_caller_id);
825                 ast_callerid_parse(caller_id, &cid_name, &cid_num);
826
827                 if (ast_is_shrinkable_phonenumber(cid_num)) {
828                         ast_shrink_phone_number(cid_num);
829                 }
830         }
831
832         if (!ast_strlen_zero(args_app)) {
833                 const char *app = "Stasis";
834
835                 RAII_VAR(struct ast_str *, appdata, ast_str_create(64), ast_free);
836
837                 if (!appdata) {
838                         ast_ari_response_alloc_failed(response);
839                         return;
840                 }
841
842                 ast_str_set(&appdata, 0, "%s", args_app);
843                 if (!ast_strlen_zero(args_app_args)) {
844                         ast_str_append(&appdata, 0, ",%s", args_app_args);
845                 }
846
847                 /* originate a channel, putting it into an application */
848                 if (ast_pbx_outgoing_app(dialtech, cap, dialdevice, timeout, app, ast_str_buffer(appdata), NULL, 0, cid_num, cid_name, variables, NULL, &chan, &assignedids)) {
849                         ast_ari_response_alloc_failed(response);
850                         return;
851                 }
852         } else if (!ast_strlen_zero(args_extension)) {
853                 /* originate a channel, sending it to an extension */
854                 if (ast_pbx_outgoing_exten(dialtech, cap, dialdevice, timeout, S_OR(args_context, "default"), args_extension, args_priority ? args_priority : 1, NULL, 0, cid_num, cid_name, variables, NULL, &chan, 0, &assignedids)) {
855                         ast_ari_response_alloc_failed(response);
856                         return;
857                 }
858         } else {
859                 ast_ari_response_error(response, 400, "Bad Request",
860                         "Application or extension must be specified");
861                 return;
862         }
863
864         /* See if this is a Local channel and if so, get the peer */
865         local_peer = ast_local_get_peer(chan);
866
867         if (!ast_strlen_zero(args_app)) {
868                 stasis_app_subscribe_channel(args_app, chan);
869                 if (local_peer) {
870                         stasis_app_subscribe_channel(args_app, local_peer);
871                 }
872         }
873
874         snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
875         ast_channel_unlock(chan);
876
877         ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot, NULL));
878         ast_channel_unref(chan);
879         if (local_peer) {
880                 ast_channel_unref(local_peer);
881         }
882 }
883
884 void ast_ari_channels_originate_with_id(struct ast_variable *headers,
885         struct ast_ari_channels_originate_with_id_args *args,
886         struct ast_ari_response *response)
887 {
888         RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
889
890         /* Parse any query parameters out of the body parameter */
891         if (args->variables) {
892                 struct ast_json *json_variables;
893
894                 ast_ari_channels_originate_with_id_parse_body(args->variables, args);
895                 json_variables = ast_json_object_get(args->variables, "variables");
896                 if (json_variables) {
897                         if (json_to_ast_variables(json_variables, &variables)) {
898                                 ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to channel variables\n");
899                                 ast_ari_response_alloc_failed(response);
900                                 return;
901                         }
902                 }
903         }
904
905         ari_channels_handle_originate_with_id(
906                 args->endpoint,
907                 args->extension,
908                 args->context,
909                 args->priority,
910                 args->app,
911                 args->app_args,
912                 args->caller_id,
913                 args->timeout,
914                 variables,
915                 args->channel_id,
916                 args->other_channel_id,
917                 response);
918 }
919
920 void ast_ari_channels_originate(struct ast_variable *headers,
921         struct ast_ari_channels_originate_args *args,
922         struct ast_ari_response *response)
923 {
924         RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
925
926         /* Parse any query parameters out of the body parameter */
927         if (args->variables) {
928                 struct ast_json *json_variables;
929
930                 ast_ari_channels_originate_parse_body(args->variables, args);
931                 json_variables = ast_json_object_get(args->variables, "variables");
932                 if (json_variables) {
933                         if (json_to_ast_variables(json_variables, &variables)) {
934                                 ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to channel variables\n");
935                                 ast_ari_response_alloc_failed(response);
936                                 return;
937                         }
938                 }
939         }
940
941         ari_channels_handle_originate_with_id(
942                 args->endpoint,
943                 args->extension,
944                 args->context,
945                 args->priority,
946                 args->app,
947                 args->app_args,
948                 args->caller_id,
949                 args->timeout,
950                 variables,
951                 args->channel_id,
952                 args->other_channel_id,
953                 response);
954 }
955
956 void ast_ari_channels_get_channel_var(struct ast_variable *headers,
957         struct ast_ari_channels_get_channel_var_args *args,
958         struct ast_ari_response *response)
959 {
960         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
961         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
962         RAII_VAR(char *, value, NULL, ast_free);
963
964         ast_assert(response != NULL);
965
966         if (ast_strlen_zero(args->variable)) {
967                 ast_ari_response_error(
968                         response, 400, "Bad Request",
969                         "Variable name is required");
970                 return;
971         }
972
973         control = find_control(response, args->channel_id);
974         if (control == NULL) {
975                 /* response filled in by find_control */
976                 return;
977         }
978
979         value = stasis_app_control_get_channel_var(control, args->variable);
980
981         if (!(json = ast_json_pack("{s: s}", "value", S_OR(value, "")))) {
982                 ast_ari_response_alloc_failed(response);
983                 return;
984         }
985
986         ast_ari_response_ok(response, ast_json_ref(json));
987 }
988
989 void ast_ari_channels_set_channel_var(struct ast_variable *headers,
990         struct ast_ari_channels_set_channel_var_args *args,
991         struct ast_ari_response *response)
992 {
993         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
994
995         ast_assert(response != NULL);
996
997         if (ast_strlen_zero(args->variable)) {
998                 ast_ari_response_error(
999                         response, 400, "Bad Request",
1000                         "Variable name is required");
1001                 return;
1002         }
1003
1004         control = find_control(response, args->channel_id);
1005         if (control == NULL) {
1006                 /* response filled in by find_control */
1007                 return;
1008         }
1009
1010         if (stasis_app_control_set_channel_var(control, args->variable, args->value)) {
1011                 ast_ari_response_error(
1012                         response, 400, "Bad Request",
1013                         "Failed to execute function");
1014                 return;
1015         }
1016
1017         ast_ari_response_no_content(response);
1018 }
1019
1020 static void ari_channels_handle_snoop_channel(
1021         const char *args_channel_id,
1022         const char *args_spy,
1023         const char *args_whisper,
1024         const char *args_app,
1025         const char *args_app_args,
1026         const char *args_snoop_id,
1027         struct ast_ari_response *response)
1028 {
1029         enum stasis_app_snoop_direction spy, whisper;
1030         RAII_VAR(struct ast_channel *, chan, NULL, ast_channel_cleanup);
1031         RAII_VAR(struct ast_channel *, snoop, NULL, ast_channel_cleanup);
1032         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
1033
1034         ast_assert(response != NULL);
1035
1036         if (ast_strlen_zero(args_spy) || !strcmp(args_spy, "none")) {
1037                 spy = STASIS_SNOOP_DIRECTION_NONE;
1038         } else if (!strcmp(args_spy, "both")) {
1039                 spy = STASIS_SNOOP_DIRECTION_BOTH;
1040         } else if (!strcmp(args_spy, "out")) {
1041                 spy = STASIS_SNOOP_DIRECTION_OUT;
1042         } else if (!strcmp(args_spy, "in")) {
1043                 spy = STASIS_SNOOP_DIRECTION_IN;
1044         } else {
1045                 ast_ari_response_error(
1046                         response, 400, "Bad Request",
1047                         "Invalid direction specified for spy");
1048                 return;
1049         }
1050
1051         if (ast_strlen_zero(args_whisper) || !strcmp(args_whisper, "none")) {
1052                 whisper = STASIS_SNOOP_DIRECTION_NONE;
1053         } else if (!strcmp(args_whisper, "both")) {
1054                 whisper = STASIS_SNOOP_DIRECTION_BOTH;
1055         } else if (!strcmp(args_whisper, "out")) {
1056                 whisper = STASIS_SNOOP_DIRECTION_OUT;
1057         } else if (!strcmp(args_whisper, "in")) {
1058                 whisper = STASIS_SNOOP_DIRECTION_IN;
1059         } else {
1060                 ast_ari_response_error(
1061                         response, 400, "Bad Request",
1062                         "Invalid direction specified for whisper");
1063                 return;
1064         }
1065
1066         if (spy == STASIS_SNOOP_DIRECTION_NONE && whisper == STASIS_SNOOP_DIRECTION_NONE) {
1067                 ast_ari_response_error(
1068                         response, 400, "Bad Request",
1069                         "Direction must be specified for at least spy or whisper");
1070                 return;
1071         } else if (ast_strlen_zero(args_app)) {
1072                 ast_ari_response_error(
1073                         response, 400, "Bad Request",
1074                         "Application name is required");
1075                 return;
1076         }
1077
1078         chan = ast_channel_get_by_name(args_channel_id);
1079         if (chan == NULL) {
1080                 ast_ari_response_error(
1081                         response, 404, "Channel Not Found",
1082                         "Provided channel was not found");
1083                 return;
1084         }
1085
1086         snoop = stasis_app_control_snoop(chan, spy, whisper, args_app, args_app_args,
1087                 args_snoop_id);
1088         if (snoop == NULL) {
1089                 ast_ari_response_error(
1090                         response, 500, "Internal error",
1091                         "Snoop channel could not be created");
1092                 return;
1093         }
1094
1095         snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(snoop));
1096         ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot, NULL));
1097 }
1098
1099 void ast_ari_channels_snoop_channel(struct ast_variable *headers,
1100         struct ast_ari_channels_snoop_channel_args *args,
1101         struct ast_ari_response *response)
1102 {
1103         ari_channels_handle_snoop_channel(
1104                 args->channel_id,
1105                 args->spy,
1106                 args->whisper,
1107                 args->app,
1108                 args->app_args,
1109                 args->snoop_id,
1110                 response);
1111 }
1112
1113 void ast_ari_channels_snoop_channel_with_id(struct ast_variable *headers,
1114         struct ast_ari_channels_snoop_channel_with_id_args *args,
1115         struct ast_ari_response *response)
1116 {
1117         ari_channels_handle_snoop_channel(
1118                 args->channel_id,
1119                 args->spy,
1120                 args->whisper,
1121                 args->app,
1122                 args->app_args,
1123                 args->snoop_id,
1124                 response);
1125 }