[asterisk-commits] markm: trunk r361038 - in /trunk: ./ include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Apr 3 14:31:29 CDT 2012


Author: markm
Date: Tue Apr  3 14:31:25 2012
New Revision: 361038

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=361038
Log:
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


Modified:
    trunk/CHANGES
    trunk/include/asterisk/channel.h
    trunk/include/asterisk/manager.h
    trunk/include/asterisk/strings.h
    trunk/main/channel.c
    trunk/main/manager.c
    trunk/main/utils.c

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=361038&r1=361037&r2=361038
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Tue Apr  3 14:31:25 2012
@@ -170,6 +170,11 @@
    returning "A" if auto_force_rport is set and nat is detected, and "a" if it is
    set and nat is not detected. "Y" and "N" are still returned if auto_force_rport
    is not enabled.
+
+ * 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.
 
 FAX changes
 -----------

Modified: trunk/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/channel.h?view=diff&rev=361038&r1=361037&r2=361038
==============================================================================
--- trunk/include/asterisk/channel.h (original)
+++ trunk/include/asterisk/channel.h Tue Apr  3 14:31:25 2012
@@ -1381,6 +1381,14 @@
 int ast_check_hangup(struct ast_channel *chan);
 
 int ast_check_hangup_locked(struct ast_channel *chan);
+
+/*!
+ * \brief Lock the given channel, then request softhangup on the channel with the given causecode
+ * \param obj channel on which to hang up
+ * \param causecode cause code to use
+ * \return 0
+ */
+int ast_channel_softhangup_withcause_locked(void *obj, int causecode);
 
 /*!
  * \brief Compare a offset with the settings of when to hang a channel up

Modified: trunk/include/asterisk/manager.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/manager.h?view=diff&rev=361038&r1=361037&r2=361038
==============================================================================
--- trunk/include/asterisk/manager.h (original)
+++ trunk/include/asterisk/manager.h Tue Apr  3 14:31:25 2012
@@ -261,6 +261,9 @@
 /*! \brief Send error in manager transaction */
 void astman_send_error(struct mansession *s, const struct message *m, char *error);
 
+/*! \brief Send error in manager transaction (with va_args support) */
+void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt, ...);
+
 /*! \brief Send response in manager transaction */
 void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg);
 

Modified: trunk/include/asterisk/strings.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/strings.h?view=diff&rev=361038&r1=361037&r2=361038
==============================================================================
--- trunk/include/asterisk/strings.h (original)
+++ trunk/include/asterisk/strings.h Tue Apr  3 14:31:25 2012
@@ -252,11 +252,26 @@
 */
 int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap) __attribute__((format(printf, 3, 0)));
 
-/*! 
+/*!
+  \brief Given a string regex_string in the form of "/regex/", convert it into the form of "regex"
+
+  This function will trim one leading / and one trailing / from a given input string
+  ast_str regex_pattern must be preallocated before calling this function
+
+  \return 0 on success, non-zero on failure.
+  \return 1 if we only stripped a leading /
+  \return 2 if we only stripped a trailing /
+  \return 3 if we did not strip any / characters
+  \param regex_string  the string containing /regex/
+  \param regex_pattern the destination ast_str which will contain "regex" after execution
+*/
+int ast_regex_string_to_regex_pattern(const char *regex_string, struct ast_str *regex_pattern);
+
+/*!
  * \brief Make sure something is true.
  * Determine if a string containing a boolean value is "true".
- * This function checks to see whether a string passed to it is an indication of an "true" value.  
- * It checks to see if the string is "yes", "true", "y", "t", "on" or "1".  
+ * This function checks to see whether a string passed to it is an indication of an "true" value.
+ * It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
  *
  * \retval 0 if val is a NULL pointer.
  * \retval -1 if "true".

Modified: trunk/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/channel.c?view=diff&rev=361038&r1=361037&r2=361038
==============================================================================
--- trunk/main/channel.c (original)
+++ trunk/main/channel.c Tue Apr  3 14:31:25 2012
@@ -602,6 +602,26 @@
 	res = ast_check_hangup(chan);
 	ast_channel_unlock(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)

Modified: trunk/main/manager.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/manager.c?view=diff&rev=361038&r1=361037&r2=361038
==============================================================================
--- trunk/main/manager.c (original)
+++ trunk/main/manager.c Tue Apr  3 14:31:25 2012
@@ -174,7 +174,9 @@
 		<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(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
 
 /*!
@@ -2107,6 +2109,23 @@
 void astman_send_error(struct mansession *s, const struct message *m, char *error)
 {
 	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)
@@ -3139,12 +3158,22 @@
 {
 	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");
-
-	if (ast_strlen_zero(name)) {
+	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_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)) {
@@ -3157,23 +3186,84 @@
 		}
 	}
 
-	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);
-	}
-	ast_softhangup_nolock(c, AST_SOFTHANGUP_EXPLICIT);
-	ast_channel_unlock(c);
-
-	c = ast_channel_unref(c);
-
-	astman_send_ack(s, m, "Channel Hungup");
+	/***********************************************/
+	/* 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;
+	}
+
+	/* 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;
+		}
+
+		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;
 }

Modified: trunk/main/utils.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/utils.c?view=diff&rev=361038&r1=361037&r2=361038
==============================================================================
--- trunk/main/utils.c (original)
+++ trunk/main/utils.c Tue Apr  3 14:31:25 2012
@@ -1348,6 +1348,26 @@
 	va_end(ap);
 
 	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)




More information about the asterisk-commits mailing list