res_ari_channels: Add ring operation, dtmf operation, hangup reasons, and tweak early...
[asterisk/asterisk.git] / res / ari / resource_channels.c
index 4d52281..482e4ba 100644 (file)
@@ -34,13 +34,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include "asterisk/file.h"
 #include "asterisk/pbx.h"
-#include "asterisk/dial.h"
 #include "asterisk/bridge.h"
 #include "asterisk/callerid.h"
 #include "asterisk/stasis_app.h"
 #include "asterisk/stasis_app_playback.h"
 #include "asterisk/stasis_app_recording.h"
 #include "asterisk/stasis_channels.h"
+#include "asterisk/causes.h"
 #include "resource_channels.h"
 
 #include <limits.h>
@@ -81,23 +81,6 @@ static struct stasis_app_control *find_control(
        return control;
 }
 
-void ast_ari_dial(struct ast_variable *headers, struct ast_dial_args *args, struct ast_ari_response *response)
-{
-       struct stasis_app_control *control;
-
-       control = find_control(response, args->channel_id);
-       if (control == NULL) {
-               return;
-       }
-
-       if (stasis_app_control_dial(control, args->endpoint, args->extension, args->context, args->timeout)) {
-               ast_ari_response_alloc_failed(response);
-               return;
-       }
-
-       ast_ari_response_no_content(response);
-}
-
 void ast_ari_continue_in_dialplan(
        struct ast_variable *headers,
        struct ast_continue_in_dialplan_args *args,
@@ -141,6 +124,22 @@ void ast_ari_answer_channel(struct ast_variable *headers,
        ast_ari_response_no_content(response);
 }
 
+void ast_ari_ring_channel(struct ast_variable *headers,
+                               struct ast_ring_channel_args *args,
+                               struct ast_ari_response *response)
+{
+       RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+       control = find_control(response, args->channel_id);
+       if (control == NULL) {
+               return;
+       }
+
+       stasis_app_control_ring(control);
+
+       ast_ari_response_no_content(response);
+}
+
 void ast_ari_mute_channel(struct ast_variable *headers, struct ast_mute_channel_args *args, struct ast_ari_response *response)
 {
        RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
@@ -152,6 +151,13 @@ void ast_ari_mute_channel(struct ast_variable *headers, struct ast_mute_channel_
                return;
        }
 
+       if (ast_strlen_zero(args->direction)) {
+               ast_ari_response_error(
+                       response, 400, "Bad Request",
+                       "Direction is required");
+               return;
+       }
+
        if (!strcmp(args->direction, "in")) {
                direction = AST_MUTE_DIRECTION_READ;
        } else if (!strcmp(args->direction, "out")) {
@@ -181,6 +187,13 @@ void ast_ari_unmute_channel(struct ast_variable *headers, struct ast_unmute_chan
                return;
        }
 
+       if (ast_strlen_zero(args->direction)) {
+               ast_ari_response_error(
+                       response, 400, "Bad Request",
+                       "Direction is required");
+               return;
+       }
+
        if (!strcmp(args->direction, "in")) {
                direction = AST_MUTE_DIRECTION_READ;
        } else if (!strcmp(args->direction, "out")) {
@@ -199,6 +212,27 @@ void ast_ari_unmute_channel(struct ast_variable *headers, struct ast_unmute_chan
        ast_ari_response_no_content(response);
 }
 
+void ast_ari_send_dtmfchannel(struct ast_variable *headers, struct ast_send_dtmfchannel_args *args, struct ast_ari_response *response)
+{
+       RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+       control = find_control(response, args->channel_id);
+       if (control == NULL) {
+               return;
+       }
+
+       if (ast_strlen_zero(args->dtmf)) {
+               ast_ari_response_error(
+                       response, 400, "Bad Request",
+                       "DTMF is required");
+               return;
+       }
+
+       stasis_app_control_dtmf(control, args->dtmf, args->before, args->between, args->duration, args->after);
+
+       ast_ari_response_no_content(response);
+}
+
 void ast_ari_hold_channel(struct ast_variable *headers, struct ast_hold_channel_args *args, struct ast_ari_response *response)
 {
        RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
@@ -393,6 +427,13 @@ void ast_ari_record_channel(struct ast_variable *headers,
                return;
        }
 
+       if (!ast_get_format_for_file_ext(options->format)) {
+               ast_ari_response_error(
+                       response, 422, "Unprocessable Entity",
+                       "specified format is unknown on this system");
+               return;
+       }
+
        recording = stasis_app_control_record(control, options);
        if (recording == NULL) {
                switch(errno) {
@@ -406,7 +447,7 @@ void ast_ari_record_channel(struct ast_variable *headers,
                        break;
                case EEXIST:
                        ast_ari_response_error(response, 409, "Conflict",
-                               "Recording '%s' already in progress",
+                               "Recording '%s' already exists and can not be overwritten",
                                args->name);
                        break;
                case ENOMEM:
@@ -498,6 +539,7 @@ void ast_ari_delete_channel(struct ast_variable *headers,
                                struct ast_ari_response *response)
 {
        RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
+       int cause;
 
        chan = ast_channel_get_by_name(args->channel_id);
        if (chan == NULL) {
@@ -507,6 +549,20 @@ void ast_ari_delete_channel(struct ast_variable *headers,
                return;
        }
 
+       if (ast_strlen_zero(args->reason) || !strcmp(args->reason, "normal")) {
+               cause = AST_CAUSE_NORMAL;
+       } else if (!strcmp(args->reason, "busy")) {
+               cause = AST_CAUSE_BUSY;
+       } else if (!strcmp(args->reason, "congestion")) {
+               cause = AST_CAUSE_CONGESTION;
+       } else {
+               ast_ari_response_error(
+                       response, 400, "Invalid Reason",
+                       "Invalid reason for hangup provided");
+               return;
+       }
+
+       ast_channel_hangupcause_set(chan, cause);
        ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
 
        ast_ari_response_no_content(response);
@@ -571,6 +627,8 @@ void ast_ari_originate(struct ast_variable *headers,
        int timeout = 30000;
 
        char *stuff;
+       struct ast_channel *chan;
+       RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
 
        if (ast_strlen_zero(args->endpoint)) {
                ast_ari_response_error(response, 400, "Bad Request",
@@ -621,13 +679,13 @@ void ast_ari_originate(struct ast_variable *headers,
                }
 
                /* originate a channel, putting it into an application */
-               if (ast_pbx_outgoing_app(dialtech, NULL, dialdevice, timeout, app, ast_str_buffer(appdata), NULL, 0, cid_num, cid_name, NULL, NULL, NULL)) {
+               if (ast_pbx_outgoing_app(dialtech, NULL, dialdevice, timeout, app, ast_str_buffer(appdata), NULL, 0, cid_num, cid_name, NULL, NULL, &chan)) {
                        ast_ari_response_alloc_failed(response);
                        return;
                }
        } else if (!ast_strlen_zero(args->extension)) {
                /* originate a channel, sending it to an extension */
-               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, NULL, 0)) {
+               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)) {
                        ast_ari_response_alloc_failed(response);
                        return;
                }
@@ -637,7 +695,20 @@ void ast_ari_originate(struct ast_variable *headers,
                return;
        }
 
-       ast_ari_response_no_content(response);
+       snapshot = ast_channel_snapshot_create(chan);
+       ast_channel_unlock(chan);
+
+       if (!ast_strlen_zero(args->app)) {
+               /* channel: + channel ID + null terminator */
+               char uri[9 + strlen(ast_channel_uniqueid(chan))];
+               const char *uris[1] = { uri, };
+
+               sprintf(uri, "channel:%s", ast_channel_uniqueid(chan));
+               stasis_app_subscribe(args->app, uris, 1, NULL);
+       }
+
+       ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot));
+       ast_channel_unref(chan);
 }
 
 void ast_ari_get_channel_var(struct ast_variable *headers, struct ast_get_channel_var_args *args, struct ast_ari_response *response)