#include <limits.h>
+/*!
+ * \brief Ensure channel is in a state that allows operation to be performed.
+ *
+ * Since Asterisk 14, it has been possible for down channels, as well as unanswered
+ * outbound channels to enter Stasis. While some operations are fine to perform on
+ * such channels, operations that
+ *
+ * - Attempt to manipulate channel state
+ * - Attempt to play media
+ * - Attempt to control the channel's location in the dialplan
+ *
+ * are invalid. This function can be used to determine if the channel is in an
+ * appropriate state.
+ *
+ * \note When this function returns an error, the HTTP response is taken care of.
+ *
+ * \param control The app control
+ * \param response Response to fill in if there is an error
+ *
+ * \retval 0 Channel is in a valid state. Continue on!
+ * \retval non-zero Channel is in an invalid state. Bail!
+ */
+static int channel_state_invalid(struct stasis_app_control *control,
+ struct ast_ari_response *response)
+{
+ struct ast_channel_snapshot *snapshot;
+
+ snapshot = stasis_app_control_get_snapshot(control);
+ if (!snapshot) {
+ ast_ari_response_error(response, 404, "Not Found", "Channel not found");
+ return -1;
+ }
+
+ /* These channel states apply only to outbound channels:
+ * - Down: Channel has been created, and nothing else has been done
+ * - Reserved: For a PRI, an underlying B-channel is reserved,
+ * but the channel is not yet dialed
+ * - Ringing: The channel has been dialed.
+ *
+ * This does not affect inbound channels. Inbound channels, when they
+ * enter the dialplan, are in the "Ring" state. If they have already
+ * been answered, then they are in the "Up" state.
+ */
+ if (snapshot->state == AST_STATE_DOWN
+ || snapshot->state == AST_STATE_RESERVED
+ || snapshot->state == AST_STATE_RINGING) {
+ ast_ari_response_error(response, 412, "Precondition Failed",
+ "Channel in invalid state");
+ return -1;
+ }
+
+ return 0;
+}
+
/*!
* \brief Finds the control object for a channel, filling the response with an
* error, if appropriate.
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
snapshot = stasis_app_control_get_snapshot(control);
if (!snapshot) {
+ ast_ari_response_error(response, 404, "Not Found", "Channel not found");
return;
}
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
if (ast_strlen_zero(args->endpoint)) {
ast_ari_response_error(response, 400, "Not Found",
"Required parameter 'endpoint' not provided.");
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
if (stasis_app_control_answer(control) != 0) {
ast_ari_response_error(
response, 500, "Internal Server Error",
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
stasis_app_control_ring(control);
ast_ari_response_no_content(response);
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
stasis_app_control_ring_stop(control);
ast_ari_response_no_content(response);
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
if (ast_strlen_zero(args->direction)) {
ast_ari_response_error(
response, 400, "Bad Request",
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
if (ast_strlen_zero(args->direction)) {
ast_ari_response_error(
response, 400, "Bad Request",
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
if (ast_strlen_zero(args->dtmf)) {
ast_ari_response_error(
response, 400, "Bad Request",
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
stasis_app_control_hold(control);
ast_ari_response_no_content(response);
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
stasis_app_control_unhold(control);
ast_ari_response_no_content(response);
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
stasis_app_control_moh_start(control, args->moh_class);
ast_ari_response_no_content(response);
}
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
stasis_app_control_moh_stop(control);
ast_ari_response_no_content(response);
}
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
stasis_app_control_silence_start(control);
ast_ari_response_no_content(response);
}
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
stasis_app_control_silence_stop(control);
ast_ari_response_no_content(response);
}
return;
}
+ if (channel_state_invalid(control, response)) {
+ return;
+ }
+
snapshot = stasis_app_control_get_snapshot(control);
if (!snapshot) {
ast_ari_response_error(
case 501: /* Not Implemented */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 404: /* Channel or endpoint not found */
case 409: /* Channel not in a Stasis application */
case 422: /* Endpoint is not the same type as the channel */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 501: /* Not Implemented */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 501: /* Not Implemented */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 501: /* Not Implemented */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 400: /* DTMF is required */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 501: /* Not Implemented */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 501: /* Not Implemented */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 501: /* Not Implemented */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 501: /* Not Implemented */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 501: /* Not Implemented */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 501: /* Not Implemented */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 501: /* Not Implemented */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 501: /* Not Implemented */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 501: /* Not Implemented */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
case 501: /* Not Implemented */
case 404: /* Channel not found */
case 409: /* Channel not in a Stasis application */
+ case 412: /* Channel in invalid state */
is_valid = 1;
break;
default:
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
}
{
"code": 422,
"reason": "Endpoint is not the same type as the channel"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
}
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
}
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
},
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
}
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
}
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
},
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
}
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
},
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
}
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
},
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
}
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
},
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
}
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
}
{
"code": 409,
"reason": "Channel not in a Stasis application"
+ },
+ {
+ "code": 412,
+ "reason": "Channel in invalid state"
}
]
}