a00b295329ebd795b218b3af616913e001508b60
[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 "resource_channels.h"
44
45 #include <limits.h>
46
47 /*!
48  * \brief Finds the control object for a channel, filling the response with an
49  * error, if appropriate.
50  * \param[out] response Response to fill with an error if control is not found.
51  * \param channel_id ID of the channel to lookup.
52  * \return Channel control object.
53  * \return \c NULL if control object does not exist.
54  */
55 static struct stasis_app_control *find_control(
56         struct ast_ari_response *response,
57         const char *channel_id)
58 {
59         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
60
61         ast_assert(response != NULL);
62
63         control = stasis_app_control_find_by_channel_id(channel_id);
64         if (control == NULL) {
65                 /* Distinguish between 404 and 409 errors */
66                 RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
67                 chan = ast_channel_get_by_name(channel_id);
68                 if (chan == NULL) {
69                         ast_ari_response_error(response, 404, "Not Found",
70                                    "Channel not found");
71                         return NULL;
72                 }
73
74                 ast_ari_response_error(response, 409, "Conflict",
75                            "Channel not in Stasis application");
76                 return NULL;
77         }
78
79         ao2_ref(control, +1);
80         return control;
81 }
82
83 void ast_ari_continue_in_dialplan(
84         struct ast_variable *headers,
85         struct ast_continue_in_dialplan_args *args,
86         struct ast_ari_response *response)
87 {
88         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
89
90         ast_assert(response != NULL);
91
92         control = find_control(response, args->channel_id);
93         if (control == NULL) {
94                 return;
95         }
96
97         if (stasis_app_control_continue(control, args->context, args->extension, args->priority)) {
98                 ast_ari_response_alloc_failed(response);
99                 return;
100         }
101
102         ast_ari_response_no_content(response);
103 }
104
105 void ast_ari_answer_channel(struct ast_variable *headers,
106                                 struct ast_answer_channel_args *args,
107                                 struct ast_ari_response *response)
108 {
109         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
110
111         control = find_control(response, args->channel_id);
112         if (control == NULL) {
113                 return;
114         }
115
116         if (stasis_app_control_answer(control) != 0) {
117                 ast_ari_response_error(
118                         response, 500, "Internal Server Error",
119                         "Failed to answer channel");
120                 return;
121         }
122
123         ast_ari_response_no_content(response);
124 }
125
126 void ast_ari_mute_channel(struct ast_variable *headers, struct ast_mute_channel_args *args, struct ast_ari_response *response)
127 {
128         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
129         unsigned int direction = 0;
130         enum ast_frame_type frametype = AST_FRAME_VOICE;
131
132         control = find_control(response, args->channel_id);
133         if (control == NULL) {
134                 return;
135         }
136
137         if (ast_strlen_zero(args->direction)) {
138                 ast_ari_response_error(
139                         response, 400, "Bad Request",
140                         "Direction is required");
141                 return;
142         }
143
144         if (!strcmp(args->direction, "in")) {
145                 direction = AST_MUTE_DIRECTION_READ;
146         } else if (!strcmp(args->direction, "out")) {
147                 direction = AST_MUTE_DIRECTION_WRITE;
148         } else if (!strcmp(args->direction, "both")) {
149                 direction = AST_MUTE_DIRECTION_READ | AST_MUTE_DIRECTION_WRITE;
150         } else {
151                 ast_ari_response_error(
152                         response, 400, "Bad Request",
153                         "Invalid direction specified");
154                 return;
155         }
156
157         stasis_app_control_mute(control, direction, frametype);
158
159         ast_ari_response_no_content(response);
160 }
161
162 void ast_ari_unmute_channel(struct ast_variable *headers, struct ast_unmute_channel_args *args, struct ast_ari_response *response)
163 {
164         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
165         unsigned int direction = 0;
166         enum ast_frame_type frametype = AST_FRAME_VOICE;
167
168         control = find_control(response, args->channel_id);
169         if (control == NULL) {
170                 return;
171         }
172
173         if (ast_strlen_zero(args->direction)) {
174                 ast_ari_response_error(
175                         response, 400, "Bad Request",
176                         "Direction is required");
177                 return;
178         }
179
180         if (!strcmp(args->direction, "in")) {
181                 direction = AST_MUTE_DIRECTION_READ;
182         } else if (!strcmp(args->direction, "out")) {
183                 direction = AST_MUTE_DIRECTION_WRITE;
184         } else if (!strcmp(args->direction, "both")) {
185                 direction = AST_MUTE_DIRECTION_READ | AST_MUTE_DIRECTION_WRITE;
186         } else {
187                 ast_ari_response_error(
188                         response, 400, "Bad Request",
189                         "Invalid direction specified");
190                 return;
191         }
192
193         stasis_app_control_unmute(control, direction, frametype);
194
195         ast_ari_response_no_content(response);
196 }
197
198 void ast_ari_hold_channel(struct ast_variable *headers, struct ast_hold_channel_args *args, struct ast_ari_response *response)
199 {
200         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
201
202         control = find_control(response, args->channel_id);
203         if (control == NULL) {
204                 /* Response filled in by find_control */
205                 return;
206         }
207
208         stasis_app_control_hold(control);
209
210         ast_ari_response_no_content(response);
211 }
212
213 void ast_ari_unhold_channel(struct ast_variable *headers, struct ast_unhold_channel_args *args, struct ast_ari_response *response)
214 {
215         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
216
217         control = find_control(response, args->channel_id);
218         if (control == NULL) {
219                 /* Response filled in by find_control */
220                 return;
221         }
222
223         stasis_app_control_unhold(control);
224
225         ast_ari_response_no_content(response);
226 }
227
228 void ast_ari_moh_start_channel(struct ast_variable *headers, struct ast_moh_start_channel_args *args, struct ast_ari_response *response)
229 {
230         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
231
232         control = find_control(response, args->channel_id);
233         if (control == NULL) {
234                 /* Response filled in by find_control */
235                 return;
236         }
237
238         stasis_app_control_moh_start(control, args->moh_class);
239         ast_ari_response_no_content(response);
240 }
241
242 void ast_ari_moh_stop_channel(struct ast_variable *headers, struct ast_moh_stop_channel_args *args, struct ast_ari_response *response)
243 {
244         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
245
246         control = find_control(response, args->channel_id);
247         if (control == NULL) {
248                 /* Response filled in by find_control */
249                 return;
250         }
251
252         stasis_app_control_moh_stop(control);
253         ast_ari_response_no_content(response);
254 }
255
256 void ast_ari_play_on_channel(struct ast_variable *headers,
257         struct ast_play_on_channel_args *args,
258         struct ast_ari_response *response)
259 {
260         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
261         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
262         RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
263         RAII_VAR(char *, playback_url, NULL, ast_free);
264         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
265         const char *language;
266
267         ast_assert(response != NULL);
268
269         control = find_control(response, args->channel_id);
270         if (control == NULL) {
271                 /* Response filled in by find_control */
272                 return;
273         }
274
275         snapshot = stasis_app_control_get_snapshot(control);
276         if (!snapshot) {
277                 ast_ari_response_error(
278                         response, 404, "Not Found",
279                         "Channel not found");
280                 return;
281         }
282
283         if (args->skipms < 0) {
284                 ast_ari_response_error(
285                         response, 400, "Bad Request",
286                         "skipms cannot be negative");
287                 return;
288         }
289
290         if (args->offsetms < 0) {
291                 ast_ari_response_error(
292                         response, 400, "Bad Request",
293                         "offsetms cannot be negative");
294                 return;
295         }
296
297         language = S_OR(args->lang, snapshot->language);
298
299         playback = stasis_app_control_play_uri(control, args->media, language,
300                 args->channel_id, STASIS_PLAYBACK_TARGET_CHANNEL, args->skipms, args->offsetms);
301         if (!playback) {
302                 ast_ari_response_error(
303                         response, 500, "Internal Server Error",
304                         "Failed to queue media for playback");
305                 return;
306         }
307
308         ast_asprintf(&playback_url, "/playback/%s",
309                 stasis_app_playback_get_id(playback));
310         if (!playback_url) {
311                 ast_ari_response_error(
312                         response, 500, "Internal Server Error",
313                         "Out of memory");
314                 return;
315         }
316
317         json = stasis_app_playback_to_json(playback);
318         if (!json) {
319                 ast_ari_response_error(
320                         response, 500, "Internal Server Error",
321                         "Out of memory");
322                 return;
323         }
324
325         ast_ari_response_created(response, playback_url, json);
326 }
327
328 void ast_ari_record_channel(struct ast_variable *headers,
329         struct ast_record_channel_args *args,
330         struct ast_ari_response *response)
331 {
332         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
333         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
334         RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
335         RAII_VAR(char *, recording_url, NULL, ast_free);
336         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
337         RAII_VAR(struct stasis_app_recording_options *, options, NULL,
338                 ao2_cleanup);
339         RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
340         size_t uri_name_maxlen;
341
342         ast_assert(response != NULL);
343
344         if (args->max_duration_seconds < 0) {
345                 ast_ari_response_error(
346                         response, 400, "Bad Request",
347                         "max_duration_seconds cannot be negative");
348                 return;
349         }
350
351         if (args->max_silence_seconds < 0) {
352                 ast_ari_response_error(
353                         response, 400, "Bad Request",
354                         "max_silence_seconds cannot be negative");
355                 return;
356         }
357
358         control = find_control(response, args->channel_id);
359         if (control == NULL) {
360                 /* Response filled in by find_control */
361                 return;
362         }
363
364         options = stasis_app_recording_options_create(args->name, args->format);
365         if (options == NULL) {
366                 ast_ari_response_error(
367                         response, 500, "Internal Server Error",
368                         "Out of memory");
369         }
370         options->max_silence_seconds = args->max_silence_seconds;
371         options->max_duration_seconds = args->max_duration_seconds;
372         options->terminate_on =
373                 stasis_app_recording_termination_parse(args->terminate_on);
374         options->if_exists =
375                 stasis_app_recording_if_exists_parse(args->if_exists);
376         options->beep = args->beep;
377
378         if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
379                 ast_ari_response_error(
380                         response, 400, "Bad Request",
381                         "terminateOn invalid");
382                 return;
383         }
384
385         if (options->if_exists == -1) {
386                 ast_ari_response_error(
387                         response, 400, "Bad Request",
388                         "ifExists invalid");
389                 return;
390         }
391
392         if (!ast_get_format_for_file_ext(options->format)) {
393                 ast_ari_response_error(
394                         response, 422, "Unprocessable Entity",
395                         "specified format is unknown on this system");
396                 return;
397         }
398
399         recording = stasis_app_control_record(control, options);
400         if (recording == NULL) {
401                 switch(errno) {
402                 case EINVAL:
403                         /* While the arguments are invalid, we should have
404                          * caught them prior to calling record.
405                          */
406                         ast_ari_response_error(
407                                 response, 500, "Internal Server Error",
408                                 "Error parsing request");
409                         break;
410                 case EEXIST:
411                         ast_ari_response_error(response, 409, "Conflict",
412                                 "Recording '%s' already exists and can not be overwritten",
413                                 args->name);
414                         break;
415                 case ENOMEM:
416                         ast_ari_response_error(
417                                 response, 500, "Internal Server Error",
418                                 "Out of memory");
419                         break;
420                 case EPERM:
421                         ast_ari_response_error(
422                                 response, 400, "Bad Request",
423                                 "Recording name invalid");
424                         break;
425                 default:
426                         ast_log(LOG_WARNING,
427                                 "Unrecognized recording error: %s\n",
428                                 strerror(errno));
429                         ast_ari_response_error(
430                                 response, 500, "Internal Server Error",
431                                 "Internal Server Error");
432                         break;
433                 }
434                 return;
435         }
436
437         uri_name_maxlen = strlen(args->name) * 3;
438         uri_encoded_name = ast_malloc(uri_name_maxlen);
439         if (!uri_encoded_name) {
440                 ast_ari_response_error(
441                         response, 500, "Internal Server Error",
442                         "Out of memory");
443                 return;
444         }
445         ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen,
446                 ast_uri_http);
447
448         ast_asprintf(&recording_url, "/recordings/live/%s", uri_encoded_name);
449         if (!recording_url) {
450                 ast_ari_response_error(
451                         response, 500, "Internal Server Error",
452                         "Out of memory");
453                 return;
454         }
455
456         json = stasis_app_recording_to_json(recording);
457         if (!json) {
458                 ast_ari_response_error(
459                         response, 500, "Internal Server Error",
460                         "Out of memory");
461                 return;
462         }
463
464         ast_ari_response_created(response, recording_url, json);
465 }
466
467 void ast_ari_get_channel(struct ast_variable *headers,
468                              struct ast_get_channel_args *args,
469                              struct ast_ari_response *response)
470 {
471         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
472         struct stasis_cache *cache;
473         struct ast_channel_snapshot *snapshot;
474
475         cache = ast_channel_cache();
476         if (!cache) {
477                 ast_ari_response_error(
478                         response, 500, "Internal Server Error",
479                         "Message bus not initialized");
480                 return;
481         }
482
483         msg = stasis_cache_get(cache, ast_channel_snapshot_type(),
484                                args->channel_id);
485         if (!msg) {
486                 ast_ari_response_error(
487                         response, 404, "Not Found",
488                         "Channel not found");
489                 return;
490         }
491
492         snapshot = stasis_message_data(msg);
493         ast_assert(snapshot != NULL);
494
495         ast_ari_response_ok(response,
496                                 ast_channel_snapshot_to_json(snapshot));
497 }
498
499 void ast_ari_delete_channel(struct ast_variable *headers,
500                                 struct ast_delete_channel_args *args,
501                                 struct ast_ari_response *response)
502 {
503         RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
504
505         chan = ast_channel_get_by_name(args->channel_id);
506         if (chan == NULL) {
507                 ast_ari_response_error(
508                         response, 404, "Not Found",
509                         "Channel not found");
510                 return;
511         }
512
513         ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
514
515         ast_ari_response_no_content(response);
516 }
517
518 void ast_ari_get_channels(struct ast_variable *headers,
519                               struct ast_get_channels_args *args,
520                               struct ast_ari_response *response)
521 {
522         RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
523         RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
524         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
525         struct ao2_iterator i;
526         void *obj;
527
528         cache = ast_channel_cache();
529         if (!cache) {
530                 ast_ari_response_error(
531                         response, 500, "Internal Server Error",
532                         "Message bus not initialized");
533                 return;
534         }
535         ao2_ref(cache, +1);
536
537         snapshots = stasis_cache_dump(cache, ast_channel_snapshot_type());
538         if (!snapshots) {
539                 ast_ari_response_alloc_failed(response);
540                 return;
541         }
542
543         json = ast_json_array_create();
544         if (!json) {
545                 ast_ari_response_alloc_failed(response);
546                 return;
547         }
548
549         i = ao2_iterator_init(snapshots, 0);
550         while ((obj = ao2_iterator_next(&i))) {
551                 RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
552                 struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
553                 int r = ast_json_array_append(
554                         json, ast_channel_snapshot_to_json(snapshot));
555                 if (r != 0) {
556                         ast_ari_response_alloc_failed(response);
557                         return;
558                 }
559         }
560         ao2_iterator_destroy(&i);
561
562         ast_ari_response_ok(response, ast_json_ref(json));
563 }
564
565 void ast_ari_originate(struct ast_variable *headers,
566                            struct ast_originate_args *args,
567                            struct ast_ari_response *response)
568 {
569         char *dialtech;
570         char dialdevice[AST_CHANNEL_NAME];
571         char *caller_id = NULL;
572         char *cid_num = NULL;
573         char *cid_name = NULL;
574         int timeout = 30000;
575
576         char *stuff;
577         struct ast_channel *chan;
578         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
579
580         if (ast_strlen_zero(args->endpoint)) {
581                 ast_ari_response_error(response, 400, "Bad Request",
582                         "Endpoint must be specified");
583                 return;
584         }
585
586         dialtech = ast_strdupa(args->endpoint);
587         if ((stuff = strchr(dialtech, '/'))) {
588                 *stuff++ = '\0';
589                 ast_copy_string(dialdevice, stuff, sizeof(dialdevice));
590         }
591
592         if (ast_strlen_zero(dialtech) || ast_strlen_zero(dialdevice)) {
593                 ast_ari_response_error(response, 400, "Bad Request",
594                         "Invalid endpoint specified");
595                 return;
596         }
597
598         if (args->timeout > 0) {
599                 timeout = args->timeout * 1000;
600         } else if (args->timeout == -1) {
601                 timeout = -1;
602         }
603
604         if (!ast_strlen_zero(args->caller_id)) {
605                 caller_id = ast_strdupa(args->caller_id);
606                 ast_callerid_parse(caller_id, &cid_name, &cid_num);
607
608                 if (ast_is_shrinkable_phonenumber(cid_num)) {
609                         ast_shrink_phone_number(cid_num);
610                 }
611         }
612
613         if (!ast_strlen_zero(args->app)) {
614                 const char *app = "Stasis";
615
616                 RAII_VAR(struct ast_str *, appdata, ast_str_create(64), ast_free);
617
618                 if (!appdata) {
619                         ast_ari_response_alloc_failed(response);
620                         return;
621                 }
622
623                 ast_str_set(&appdata, 0, "%s", args->app);
624                 if (!ast_strlen_zero(args->app_args)) {
625                         ast_str_append(&appdata, 0, ",%s", args->app_args);
626                 }
627
628                 /* originate a channel, putting it into an application */
629                 if (ast_pbx_outgoing_app(dialtech, NULL, dialdevice, timeout, app, ast_str_buffer(appdata), NULL, 0, cid_num, cid_name, NULL, NULL, &chan)) {
630                         ast_ari_response_alloc_failed(response);
631                         return;
632                 }
633         } else if (!ast_strlen_zero(args->extension)) {
634                 /* originate a channel, sending it to an extension */
635                 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)) {
636                         ast_ari_response_alloc_failed(response);
637                         return;
638                 }
639         } else {
640                 ast_ari_response_error(response, 400, "Bad Request",
641                         "Application or extension must be specified");
642                 return;
643         }
644
645         if (!ast_strlen_zero(args->app)) {
646                 /* channel: + channel ID + null terminator */
647                 char uri[9 + strlen(ast_channel_uniqueid(chan))];
648                 const char *uris[1] = { uri, };
649
650                 sprintf(uri, "channel:%s", ast_channel_uniqueid(chan));
651                 stasis_app_subscribe(args->app, uris, 1, NULL);
652         }
653
654         snapshot = ast_channel_snapshot_create(chan);
655         ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot));
656
657         ast_channel_unlock(chan);
658         ast_channel_unref(chan);
659 }
660
661 void ast_ari_get_channel_var(struct ast_variable *headers, struct ast_get_channel_var_args *args, struct ast_ari_response *response)
662 {
663         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
664         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
665         RAII_VAR(char *, value, NULL, ast_free);
666
667         ast_assert(response != NULL);
668
669         if (ast_strlen_zero(args->variable)) {
670                 ast_ari_response_error(
671                         response, 400, "Bad Request",
672                         "Variable name is required");
673                 return;
674         }
675
676         control = find_control(response, args->channel_id);
677         if (control == NULL) {
678                 /* response filled in by find_control */
679                 return;
680         }
681
682         value = stasis_app_control_get_channel_var(control, args->variable);
683
684         if (!(json = ast_json_pack("{s: s}", "value", S_OR(value, "")))) {
685                 ast_ari_response_alloc_failed(response);
686                 return;
687         }
688
689         ast_ari_response_ok(response, ast_json_ref(json));
690 }
691
692 void ast_ari_set_channel_var(struct ast_variable *headers, struct ast_set_channel_var_args *args, struct ast_ari_response *response)
693 {
694         RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
695
696         ast_assert(response != NULL);
697
698         if (ast_strlen_zero(args->variable)) {
699                 ast_ari_response_error(
700                         response, 400, "Bad Request",
701                         "Variable name is required");
702                 return;
703         }
704
705         control = find_control(response, args->channel_id);
706         if (control == NULL) {
707                 /* response filled in by find_control */
708                 return;
709         }
710
711         if (stasis_app_control_set_channel_var(control, args->variable, args->value)) {
712                 ast_ari_response_error(
713                         response, 400, "Bad Request",
714                         "Failed to execute function");
715                 return;
716         }
717
718         ast_ari_response_no_content(response);
719 }
720