summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorMark Murawki <markm@intellasoft.net>2012-04-03 19:31:25 +0000
committerMark Murawki <markm@intellasoft.net>2012-04-03 19:31:25 +0000
commite4252eac1010af969007afb525871242855d39e7 (patch)
tree27f4bcb1ede2c708c34454ba98e5880a7df836a5 /main
parent9cc6f2c59e41c0d5fa34f03950131a4eb81cc7ab (diff)
Allow the Hangup manager action to match channels by regex
* Hangup now can take a regular expression as the Channel option. If you want to hangup multiple channels, use /regex/ as the Channel option. Existing behavior to hanging up a single channel is unchanged, but if you pass a regex, the manager will send you a list of channels back that were hung up. (closes issue ASTERISK-19575) Reported by: Mark Murawski Tested by: Mark Murawski git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@361038 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r--main/channel.c20
-rw-r--r--main/manager.c120
-rw-r--r--main/utils.c20
3 files changed, 145 insertions, 15 deletions
diff --git a/main/channel.c b/main/channel.c
index 233acc768..b86cd5252 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -604,6 +604,26 @@ int ast_check_hangup_locked(struct ast_channel *chan)
return res;
}
+int ast_channel_softhangup_withcause_locked(void *obj, int causecode)
+{
+ struct ast_channel *chan = obj;
+
+ ast_channel_lock(chan);
+
+ if (causecode > 0) {
+ ast_debug(1, "Setting hangupcause of channel %s to %d (is %d now)\n",
+ ast_channel_name(chan), causecode, ast_channel_hangupcause(chan));
+
+ ast_channel_hangupcause_set(chan, causecode);
+ }
+
+ ast_softhangup_nolock(chan, AST_SOFTHANGUP_EXPLICIT);
+
+ ast_channel_unlock(chan);
+
+ return 0;
+}
+
static int ast_channel_softhangup_cb(void *obj, void *arg, int flags)
{
struct ast_channel *chan = obj;
diff --git a/main/manager.c b/main/manager.c
index 2b4904256..413adf29c 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -174,7 +174,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<syntax>
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
<parameter name="Channel" required="true">
- <para>The channel name to be hangup.</para>
+ <para>The exact channel name to be hungup, or to use a regular expression, set this parameter to: /regex/</para>
+ <para>Example exact channel: SIP/provider-0000012a</para>
+ <para>Example regular expression: /^SIP/provider-.*$/</para>
</parameter>
<parameter name="Cause">
<para>Numeric hangup cause.</para>
@@ -2034,7 +2036,7 @@ AST_THREADSTORAGE(astman_append_buf);
AST_THREADSTORAGE(userevent_buf);
-/*! \brief initial allocated size for the astman_append_buf */
+/*! \brief initial allocated size for the astman_append_buf and astman_send_*_va */
#define ASTMAN_APPEND_BUF_INITSIZE 256
/*!
@@ -2109,6 +2111,23 @@ void astman_send_error(struct mansession *s, const struct message *m, char *erro
astman_send_response_full(s, m, "Error", error, NULL);
}
+void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt, ...)
+{
+ va_list ap;
+ struct ast_str *buf;
+
+ if (!(buf = ast_str_thread_get(&astman_append_buf, ASTMAN_APPEND_BUF_INITSIZE))) {
+ return;
+ }
+
+ va_start(ap, fmt);
+ ast_str_set_va(&buf, 0, fmt, ap);
+ va_end(ap);
+
+ astman_send_response_full(s, m, "Error", ast_str_buffer(buf), NULL);
+ ast_free(buf);
+}
+
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
{
astman_send_response_full(s, m, "Success", msg, NULL);
@@ -3139,14 +3158,24 @@ static int action_hangup(struct mansession *s, const struct message *m)
{
struct ast_channel *c = NULL;
int causecode = 0; /* all values <= 0 mean 'do not set hangupcause in channel' */
- const char *name = astman_get_header(m, "Channel");
+ const char *id = astman_get_header(m, "ActionID");
+ const char *name_or_regex = astman_get_header(m, "Channel");
const char *cause = astman_get_header(m, "Cause");
+ char idText[256] = "";
+ regex_t regexbuf;
+ struct ast_channel_iterator *iter = NULL;
+ struct ast_str *regex_string;
+ int channels_matched = 0;
- if (ast_strlen_zero(name)) {
+ if (ast_strlen_zero(name_or_regex)) {
astman_send_error(s, m, "No channel specified");
return 0;
}
+ if (!ast_strlen_zero(id)) {
+ snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
+ }
+
if (!ast_strlen_zero(cause)) {
char *endptr;
causecode = strtol(cause, &endptr, 10);
@@ -3157,23 +3186,84 @@ static int action_hangup(struct mansession *s, const struct message *m)
}
}
- if (!(c = ast_channel_get_by_name(name))) {
- astman_send_error(s, m, "No such channel");
+ /************************************************/
+ /* Regular explicit match channel byname hangup */
+
+ if (name_or_regex[0] != '/') {
+ if (!(c = ast_channel_get_by_name(name_or_regex))) {
+ astman_send_error(s, m, "No such channel");
+ return 0;
+ }
+
+ ast_verb(3, "%sManager '%s' from %s, hanging up channel: %s\n",
+ (s->session->managerid ? "HTTP " : ""),
+ s->session->username,
+ ast_inet_ntoa(s->session->sin.sin_addr),
+ ast_channel_name(c));
+
+ ast_channel_softhangup_withcause_locked(c, causecode);
+ c = ast_channel_unref(c);
+
+ astman_send_ack(s, m, "Channel Hungup");
+
return 0;
}
- ast_channel_lock(c);
- if (causecode > 0) {
- ast_debug(1, "Setting hangupcause of channel %s to %d (is %d now)\n",
- ast_channel_name(c), causecode, ast_channel_hangupcause(c));
- ast_channel_hangupcause_set(c, causecode);
+ /***********************************************/
+ /* find and hangup any channels matching regex */
+
+ regex_string = ast_str_create(strlen(name_or_regex));
+
+ /* Make "/regex/" into "regex" */
+ if (ast_regex_string_to_regex_pattern(name_or_regex, regex_string) != 0) {
+ astman_send_error(s, m, "Regex format invalid, Channel param should be /regex/");
+ ast_free(regex_string);
+ return 0;
}
- ast_softhangup_nolock(c, AST_SOFTHANGUP_EXPLICIT);
- ast_channel_unlock(c);
- c = ast_channel_unref(c);
+ /* if regex compilation fails, hangup fails */
+ if (regcomp(&regexbuf, ast_str_buffer(regex_string), REG_EXTENDED | REG_NOSUB)) {
+ astman_send_error_va(s, m, "Regex compile failed on: %s\n", name_or_regex);
+ ast_free(regex_string);
+ return 0;
+ }
+
+ astman_send_listack(s, m, "Channels hung up will follow", "start");
+
+ for (iter = ast_channel_iterator_all_new(); iter && (c = ast_channel_iterator_next(iter)); ) {
+ if (regexec(&regexbuf, ast_channel_name(c), 0, NULL, 0)) {
+ ast_channel_unref(c);
+ continue;
+ }
- astman_send_ack(s, m, "Channel Hungup");
+ ast_verb(3, "%sManager '%s' from %s, hanging up channel: %s\n",
+ (s->session->managerid ? "HTTP " : ""),
+ s->session->username,
+ ast_inet_ntoa(s->session->sin.sin_addr),
+ ast_channel_name(c));
+
+ ast_channel_softhangup_withcause_locked(c, causecode);
+ channels_matched++;
+
+ astman_append(s,
+ "Event: ChannelHungup\r\n"
+ "Channel: %s\r\n"
+ "%s"
+ "\r\n", ast_channel_name(c), idText);
+
+ ast_channel_unref(c);
+ }
+
+ ast_channel_iterator_destroy(iter);
+ regfree(&regexbuf);
+ ast_free(regex_string);
+
+ astman_append(s,
+ "Event: ChannelsHungupListComplete\r\n"
+ "EventList: Complete\r\n"
+ "ListItems: %d\r\n"
+ "%s"
+ "\r\n", channels_matched, idText);
return 0;
}
diff --git a/main/utils.c b/main/utils.c
index ffcd37c2a..379a17995 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -1350,6 +1350,26 @@ int ast_build_string(char **buffer, size_t *space, const char *fmt, ...)
return result;
}
+int ast_regex_string_to_regex_pattern(const char *regex_string, struct ast_str *regex_pattern)
+{
+ int regex_len = strlen(regex_string);
+ int ret = 3;
+
+ /* Chop off the leading / if there is one */
+ if ((regex_len >= 1) && (regex_string[0] == '/')) {
+ ast_str_set(&regex_pattern, 0, "%s", regex_string + 1);
+ ret -= 2;
+ }
+
+ /* Chop off the ending / if there is one */
+ if ((regex_len > 1) && (regex_string[regex_len - 1] == '/')) {
+ ast_str_truncate(regex_pattern, -1);
+ ret -= 1;
+ }
+
+ return ret;
+}
+
int ast_true(const char *s)
{
if (ast_strlen_zero(s))