[Asterisk-code-review] chan_dahdi: Add DAHDIBusyOut (asterisk[master])

Mark Murawski asteriskteam at digium.com
Thu Sep 15 17:42:37 CDT 2022


Mark Murawski has uploaded this change for review. ( https://gerrit.asterisk.org/c/asterisk/+/19264 )


Change subject: chan_dahdi: Add DAHDIBusyOut
......................................................................

chan_dahdi: Add DAHDIBusyOut

This feature will 'busy out' a DAHDI channel in the traditional
PSTN/ISDN sense of making the line completely unavailable for
both incoming and outgoing calls.

If DAHDIBusyOut is turned on for a DAHDI channel, it will appear
for all intents and purposes that the channel is in use until
the DAHDIBusyOut is turned off for that channel.

The status of DAHDIBusyOut will not survive across Asterisk restarts.

Change-Id: Ib75c87c554bb18b8f65be73b4474474e7e1877b7
---
M channels/chan_dahdi.c
M channels/chan_dahdi.h
2 files changed, 546 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/64/19264/1

diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index b829aa4..cb21a0c 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -129,6 +129,8 @@
 #include "chan_dahdi.h"
 #include "dahdi/bridge_native_dahdi.h"
 
+#include "regex.h"
+
 /*** DOCUMENTATION
 	<application name="DAHDISendKeypadFacility" language="en_US">
 		<synopsis>
@@ -206,6 +208,24 @@
 			</example>
 		</description>
 	</function>
+       <manager name="DAHDIBusyOut" language="en_US">
+               <synopsis>
+                       Set BusyOut Mode on DAHDI Channel(s).
+               </synopsis>
+               <syntax>
+                       <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+                       <parameter name="DAHDIChannel" required="true">
+                               <para>DAHDI channel number(s) to change.  Comma delimited list of channels, with ability for ranges.  Example: 1,2,3  Example: 1-2,4-8</para>
+                       </parameter>
+                       <parameter name="Mode" required="true">
+                               <para>Boolean value, either enable or disable BusyOut</para>
+                        </parameter>
+               </syntax>
+               <description>
+                       <para>Enable or disable BusyOut on DAHDI channels.</para>
+                       <note><para>Valid only for analog channels.</para></note>
+               </description>
+       </manager>
 	<info name="CHANNEL" language="en_US" tech="DAHDI">
 		<enumlist>
 			<enum name="dahdi_channel">
@@ -1112,6 +1132,9 @@
 static int dahdi_func_write(struct ast_channel *chan, const char *function, char *data, const char *value);
 static int dahdi_devicestate(const char *data);
 static int dahdi_cc_callback(struct ast_channel *inbound, const char *dest, ast_cc_callback_fn callback);
+static int dahdi_set_channels_busyout(const char *channel_list, int on, int *touched_channels);
+static int dahdi_set_channel_busyout(struct dahdi_pvt *dahdi_chan, int on);
+
 
 static struct ast_channel_tech dahdi_tech = {
 	.type = "DAHDI",
@@ -5867,6 +5890,39 @@
 #endif	/* defined(HAVE_PRI) */
 }
 
+static char *dahdi_busyout_app = "DAHDIBusyOut";
+
+static int dahdi_busyout_exec(struct ast_channel *chan, const char *data)
+{
+       char *params;
+       AST_DECLARE_APP_ARGS(args,
+               AST_APP_ARG(channel);
+               AST_APP_ARG(mode);
+       );
+
+       if (ast_strlen_zero(data)) {
+               ast_log(LOG_WARNING, "DAHDIBusyOut requires two arguments!\n");
+               return -1;
+       }
+
+       params = ast_strdupa(data);
+       AST_STANDARD_APP_ARGS(args, params);
+
+       if (!args.channel) {
+               ast_log(LOG_WARNING, "DAHDIBusyOut requires a channel number!\n");
+               return -1;
+       }
+
+       if (!args.mode) {
+               ast_log(LOG_WARNING, "DAHDIBusyOut requires a mode!\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+
 #if defined(HAVE_PRI)
 static char *dahdi_send_keypad_facility_app = "DAHDISendKeypadFacility";
 
@@ -8623,6 +8679,11 @@
 	p->subs[idx].f.src = "dahdi_read";
 	p->subs[idx].f.data.ptr = NULL;
 
+        if (p->busyout) {
+               ast_mutex_unlock(&p->lock);
+               return &p->subs[idx].f;;
+       }
+
 	/* make sure it sends initial key state as first frame */
 	if ((p->radio || (p->oprmode < 0)) && (!p->firstradio))
 	{
@@ -9719,6 +9780,22 @@
 
 	if (p->dsp)
 		ast_dsp_digitreset(p->dsp);
+
+        if (p->busyout) {
+               struct ast_app *theapp;
+
+               res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
+
+               theapp = pbx_findapp("Answer");
+               res = pbx_exec(chan, theapp, NULL);
+
+               if (res) {
+                       ast_log(LOG_WARNING, "PBX exited non-zero\n");
+               }
+
+                goto quit;
+       }
+
 	switch (p->sig) {
 	case SIG_FEATD:
 	case SIG_FEATDMF:
@@ -11743,6 +11820,10 @@
 				break;
 			}
 
+                       if (i->busyout) {
+                               continue;
+                       }
+
 			if (thispass != lastpass) {
 				if (!found && ((i == last) || ((i == iflist) && !last))) {
 					last = i;
@@ -11894,6 +11975,7 @@
 					}
 					res = dahdi_get_event(i->subs[SUB_REAL].dfd);
 					ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
+
 					/* Don't hold iflock while handling init events */
 					ast_mutex_unlock(&iflock);
 					if (0 == i->mwisendactive || 0 == mwi_send_process_event(i, res)) {
@@ -15724,6 +15806,66 @@
 	return 0;
 }
 
+static int action_dahdibusyout(struct mansession *s, const struct message *m)
+{
+	const char *id = astman_get_header(m, "ActionID");
+	const char *channel_arg = astman_get_header(m, "DAHDIChannel");
+	const char *mode_arg = astman_get_header(m, "Mode");
+
+	char action_id[256] = "";
+	int touched_channels[DAHDI_MAX_SPANS];
+	int touched_channels_num = 0;
+	int on;
+	char *on_txt;
+	int i;
+
+	if (ast_strlen_zero(channel_arg)) {
+		astman_send_error(s, m, "DAHDIBusyOut requires: DAHDIChannel");
+		return 1;
+	}
+
+	if (ast_strlen_zero(mode_arg)) {
+		astman_send_error(s, m, "DAHDIBusyOut requires: Mode");
+		return 1;
+	}
+
+	if (!ast_strlen_zero(id)) {
+		snprintf(action_id, sizeof(action_id), "ActionID: %s\r\n", id);
+	}
+
+	on = ast_true(mode_arg) ? 1 : 0;
+	on_txt = (on ? "On": "Off");
+
+	astman_send_listack(s, m, "Dahdi BusyOut channels will follow", "start");
+
+	dahdi_set_channels_busyout(channel_arg, on, touched_channels);
+
+	for (i = 0; i < DAHDI_MAX_SPANS; i++) {
+	       if (touched_channels[i] == 0) {
+		       continue;
+	       }
+
+	       /* touched_channels[channel] is going to be either -1 (failure), 0 (no change), 1 (set), or 2 (queued) */
+	       astman_append(s,
+		       "Event: DahdiBusyOutChannel\r\n"
+		       "Channel: %d\r\n"
+		       "BusyOut: %s\r\n"
+		       "%s"
+		       "\r\n", i, (touched_channels[i] == 2 ? "Queued" : on_txt), action_id);
+
+	       touched_channels_num++;
+	}
+
+       astman_append(s,
+	       "Event: DahdiBusyOutChannelListComplete\r\n"
+	       "EventList: Complete\r\n"
+	       "ListItems: %d\r\n"
+	       "%s"
+	       "\r\n", touched_channels_num, action_id);
+
+       return 0;
+}
+
 static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 #define FORMAT "%7s %-15.15s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s %-32.32s\n"
@@ -16372,6 +16514,55 @@
 	return CLI_SUCCESS;
 }
 
+struct dahdi_found_channel {
+       AST_LIST_ENTRY(dahdi_found_channel) entries;    /*!< Next group */
+       int channel_num;                                /*!< Index into dahdi iflist */
+};
+
+AST_LIST_HEAD(dahdi_channel_list, dahdi_found_channel);
+
+static char *dahdi_set_busy(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+       int on;
+
+       switch (cmd) {
+       case CLI_INIT:
+               e->command = "dahdi set busyout";
+               e->usage =
+                       "Usage: dahdi set busyout <chan#> <on|off>\n"
+                       "       Sets/resets Busyout mode on a channel.\n"
+                       "       Changes take effect immediately.\n"
+                       "       <chan num> is the channel number\n"
+                       "       <chan num> can also be a comma delimited list of channels, ex 1,4,7\n"
+                       "       <chan num> can also be a range of channels, ex 1-8\n"
+                       "       <chan num> can also be a mix of channels and ranges, ex 1-2,4-8\n"
+                       "       <chan num> can also be 'all'\n"
+                       "       <on|off> Enable or disable Busyout mode?\n"
+                       ;
+               return NULL;
+       case CLI_GENERATE:
+               return NULL;
+       }
+
+       if (a->argc != 5)
+               return CLI_SHOWUSAGE;
+
+       if (ast_true(a->argv[4]))
+               on = 1;
+       else if (ast_false(a->argv[4]))
+               on = 0;
+       else {
+               ast_cli(a->fd, "Expected 'on' or 'off', got '%s'\n", a->argv[4]);
+               return CLI_SHOWUSAGE;
+       }
+
+        if (dahdi_set_channels_busyout(a->argv[3], on, NULL) == 0) {
+               ast_cli(a->fd, "Unable to find channels matching: %s\n", a->argv[3]);
+       }
+
+       return CLI_SUCCESS;
+}
+
 static struct ast_cli_entry dahdi_cli[] = {
 	AST_CLI_DEFINE(handle_dahdi_show_cadences, "List cadences"),
 	AST_CLI_DEFINE(dahdi_show_channels, "Show active DAHDI channels"),
@@ -16384,6 +16575,7 @@
 	AST_CLI_DEFINE(dahdi_set_hwgain, "Set hardware gain on a channel"),
 	AST_CLI_DEFINE(dahdi_set_swgain, "Set software gain on a channel"),
 	AST_CLI_DEFINE(dahdi_set_dnd, "Sets/resets DND (Do Not Disturb) mode on a channel"),
+       AST_CLI_DEFINE(dahdi_set_busy, "Sets/resets Busyout mode on a channel"),
 };
 
 #define TRANSFER	0
@@ -17705,6 +17897,7 @@
 		}
 	}
 	ast_cli_unregister_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
+       ast_unregister_application(dahdi_busyout_app);
 	ast_unregister_application(dahdi_send_keypad_facility_app);
 #ifdef HAVE_PRI_PROG_W_CAUSE
 	ast_unregister_application(dahdi_send_callrerouting_facility_app);
@@ -17735,6 +17928,7 @@
 	ast_manager_unregister("DAHDIDNDon");
 	ast_manager_unregister("DAHDIShowChannels");
 	ast_manager_unregister("DAHDIRestart");
+       ast_manager_unregister("DAHDIBusyOut");
 #if defined(HAVE_PRI)
 	ast_manager_unregister("PRIShowSpans");
 	ast_manager_unregister("PRIDebugSet");
@@ -19860,6 +20054,7 @@
 	}
 	pri_set_error(dahdi_pri_error);
 	pri_set_message(dahdi_pri_message);
+       ast_register_application_xml(dahdi_busyout_app, dahdi_busyout_exec);
 	ast_register_application_xml(dahdi_send_keypad_facility_app, dahdi_send_keypad_facility_exec);
 #ifdef HAVE_PRI_PROG_W_CAUSE
 	ast_register_application_xml(dahdi_send_callrerouting_facility_app, dahdi_send_callrerouting_facility_exec);
@@ -19926,6 +20121,7 @@
 	ast_manager_register_xml("DAHDIDNDoff", 0, action_dahdidndoff);
 	ast_manager_register_xml("DAHDIShowChannels", 0, action_dahdishowchannels);
 	ast_manager_register_xml("DAHDIRestart", 0, action_dahdirestart);
+       ast_manager_register_xml("DAHDIBusyOut", 0, action_dahdibusyout);
 #if defined(HAVE_PRI)
 	ast_manager_register_xml("PRIShowSpans", 0, action_prishowspans);
 	ast_manager_register_xml("PRIDebugSet", 0, action_pri_debug_set);
@@ -20058,6 +20254,322 @@
 	return(0);
 }
 
+/*! \brief Do the actual busyout thread creation
+ *
+ * \note Lock dahdi_chan->lock before calling
+ */
+static int dahdi_busyout_start(struct dahdi_pvt *dahdi_chan)
+{
+        int result;
+        struct ast_channel *chan;
+        pthread_t threadid;
+
+        dahdi_chan->busyout_queued = 0;
+
+	if ((chan = dahdi_new(dahdi_chan, AST_STATE_RING, 0, SUB_REAL, 0, NULL, NULL, NULL))) {
+                ast_log(LOG_WARNING, "Could not create channel to handle call\n");
+                return -1;
+        }
+
+        dahdi_chan->_busydetect = dahdi_chan->busydetect;
+        dahdi_chan->busydetect = 0;
+        dahdi_chan->busyout    = 1;
+        ast_devstate_changed(AST_STATE_BUSY, AST_DEVSTATE_NOT_CACHABLE, "DAHDI/%d/busyout", dahdi_chan->channel);
+
+        result = _ast_pthread_create_detached(&threadid, NULL, analog_ss_thread, chan);
+        if (result) {
+                ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", dahdi_chan->channel);
+                ast_hangup(chan);
+                return -1;
+        }
+
+        ast_verb(1, "<DAHDI/%d> Enabled BusyOut\n", dahdi_chan->channel);
+
+        return 0;
+}
+
+static void *dahdi_set_channel_busyout_on_thread(void *data);
+
+/*!
+ * \brief Keep trying to set busyout on a channel that's currently in use
+ *
+*/
+static void *dahdi_set_channel_busyout_on_thread(void *data)
+{
+       struct dahdi_pvt *dahdi_chan = data;
+
+       while (1) {
+               if (!dahdi_chan->busyout_queued) {
+                       /* Busyout cancelled */
+                       ast_verb(1, "<DAHDI/%d> BusyOut try thread done\n", dahdi_chan->channel);
+                       return NULL;
+               }
+
+                if (dahdi_chan->busyout) {
+                       /* Busyout already enabled */
+                       ast_verb(1, "<DAHDI/%d> BusyOut try thread done\n", dahdi_chan->channel);
+                       return NULL;
+               }
+
+               ast_mutex_lock(&dahdi_chan->lock);
+
+               if (!dahdi_chan->owner) {
+                       /* Current call finished */
+
+                       dahdi_busyout_start(dahdi_chan);
+                       ast_mutex_unlock(&dahdi_chan->lock);
+
+                       ast_verb(1, "<DAHDI/%d> BusyOut try thread done\n", dahdi_chan->channel);
+                       return NULL;
+               }
+
+               ast_mutex_unlock(&dahdi_chan->lock);
+               usleep(1000);
+       }
+
+       return NULL;
+}
+
+/*!
+ * \brief Set busyout status on a list or range of channels
+ * \param channel_list Comma delimited list of channels, may contain ranges
+ * \param touched_channels pointer to integer array preallocated to the size of DAHDI_MAX_SPANS that holds the channels changed
+ *
+ * \detail
+ *   touched_channels[channel] is going to be either -1 (failure), 0 (no change), 1 (set), or 2 (queued)
+ *
+ * \example channel_list = "1"
+ * \example channel_list = "1,2"
+ * \example channel_list = "1,2-4"
+ * \example channel_list = "1-4,6-8"
+ *
+ * \retval >0 Count of channels that have had busyout status changed
+ * \retval 0 No channel busyout status has been changed
+ */
+static int dahdi_set_channels_busyout(const char *channel_list, int on, int *touched_channels)
+{
+	int channel;
+	int channel_to;
+	int channels_touched = 0;
+	int fail_match;
+	int have_comma_remaining;
+	int i;
+	int match_comma_len;
+	int match_len;
+	int result;
+
+	char *channel_arg;
+	char *channel_arg_cur;
+	const char *match_start;
+	struct dahdi_pvt *dahdi_chan = NULL;
+	struct ast_str *match_str = ast_str_create(64);
+	struct ast_str *match_str_from = ast_str_create(64);
+	struct ast_str *match_str_to = ast_str_create(64);
+
+	regex_t regexbuf_comma;
+	regex_t regexbuf_dash;
+	regmatch_t reg_m[DAHDI_MAX_SPANS];
+	int dahdi_channels_search[DAHDI_MAX_SPANS];
+
+	channel_arg = ast_strdup(channel_list);
+	channel_arg_cur = channel_arg;
+	memset(&dahdi_channels_search, 0, sizeof(dahdi_channels_search));
+       memset(touched_channels, 0, (DAHDI_MAX_SPANS * sizeof(int)));
+
+//     ast_log(LOG_NOTICE, "channels: %s\n", channel_arg);
+
+       if (regcomp(&regexbuf_comma, "^([0-9-]+)(,|$)(.+)?", REG_EXTENDED)) {
+	       /* We should never fail */
+	       ast_log(LOG_ERROR, "Regex compile failed in dahdi_set_busy()\n");
+	       return 0;
+       }
+
+       if (regcomp(&regexbuf_dash, "^([0-9]+)-(.*)", REG_EXTENDED)) {
+	       /* We should never fail */
+	       ast_log(LOG_ERROR, "Regex compile failed in dahdi_set_busy()\n");
+	       return 0;
+       }
+
+	do {
+	       fail_match = regexec(&regexbuf_comma, channel_arg_cur, 4, reg_m, 0);
+	       if (fail_match) {
+//		       ast_log(LOG_ERROR, "regex match fail (%d): %s\n", fail_match, channel_arg_cur);
+		       break;
+	       }
+
+		match_start	 = (channel_arg_cur + reg_m[1].rm_so);
+		match_comma_len	 = (reg_m[1].rm_eo - reg_m[1].rm_so);
+		*(channel_arg_cur + match_comma_len) = 0;
+	       ast_str_set(&match_str, 0, "%s", match_start);
+//	       ast_log(LOG_NOTICE, "regex match: [%d:%d] %s (%d)\n", reg_m[1].rm_so, reg_m[1].rm_eo, ast_str_buffer(match_str), match_comma_len);
+
+		if (reg_m[3].rm_so != -1) {
+//		       ast_log(LOG_NOTICE, "Comma remaining at: %d\n", reg_m[2].rm_so);
+		       have_comma_remaining = 1;
+	       }
+		else {
+		       have_comma_remaining = 0;
+		}
+
+	       fail_match = regexec(&regexbuf_dash, ast_str_buffer(match_str), 3, reg_m, 0);
+	       if (fail_match) {
+			channel = atoi(ast_str_buffer(match_str));
+
+			if (channel && (channel < DAHDI_MAX_SPANS)) {
+			       dahdi_channels_search[channel] = 1;
+//			       ast_log(LOG_NOTICE, "num: %d\n", channel);
+			}
+	       }
+		else {
+//			  ast_log(LOG_NOTICE, "process range: %s\n", ast_str_buffer(match_str));
+
+		       match_start  = (ast_str_buffer(match_str) + reg_m[1].rm_so);
+		       match_len    = (reg_m[1].rm_eo - reg_m[1].rm_so);
+		       *(ast_str_buffer(match_str) + match_len) = 0;
+		       ast_str_set(&match_str_from, 0, "%s", match_start);
+//			  ast_log(LOG_NOTICE, "range regex match: [%d:%d] %s (%d)\n", reg_m[1].rm_so, reg_m[1].rm_eo, ast_str_buffer(match_str_from), match_len);
+
+		       match_start  = (ast_str_buffer(match_str) + reg_m[2].rm_so);
+		       match_len    = (reg_m[2].rm_eo - reg_m[2].rm_so);
+//		       *(ast_str_buffer(match_str) + match_len) = 0;
+			ast_str_set(&match_str_to, 0, "%s", match_start);
+//			  ast_log(LOG_NOTICE, "range regex match: [%d:%d] %s (%d)\n", reg_m[2].rm_so, reg_m[2].rm_eo, ast_str_buffer(match_str_to), match_len);
+
+			channel	   = atoi(ast_str_buffer(match_str_from));
+			channel_to = atoi(ast_str_buffer(match_str_to));
+
+//		       ast_log(LOG_NOTICE, "range: %d->%d\n", channel, channel_to);
+
+			if (channel && channel_to && (channel < DAHDI_MAX_SPANS) && (channel_to < DAHDI_MAX_SPANS)) {
+			       for (i = channel; i <= channel_to; i++) {
+				       dahdi_channels_search[i] = 1;
+				}
+			}
+	       }
+
+		/* skip past the current match */
+		channel_arg_cur += match_comma_len;
+
+		/* skip past the comma between matches */
+		if (have_comma_remaining) {
+		       channel_arg_cur++;
+	       }
+	}
+	while (*channel_arg_cur);
+
+//	  for (i = 0; i < DAHDI_MAX_SPANS; i++) {
+//		  if (dahdi_channels_search[i]) {
+//		       ast_log(LOG_NOTICE, "select -> %d\n", i);
+//		  }
+//	  }
+
+       ast_mutex_lock(&iflock);
+       for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
+	       channel = dahdi_chan->channel;
+	       if ((channel < 0) || !dahdi_channels_search[channel]) {
+		       continue;
+	       }
+
+	       /* Found the channel. Actually set it */
+		channels_touched++;
+		ast_verb(1, "<DAHDI/%d> Setting BusyOut Mode to: %s\n", channel, (on ? "On" : "Off"));
+		result = dahdi_set_channel_busyout(dahdi_chan, on);
+
+		if (touched_channels) {
+		       /* -1 (failure), 0 (no change), 1 (set), or 2 (queued) */
+		       touched_channels[channel] = result;
+		}
+	}
+	ast_mutex_unlock(&iflock);
+
+	regfree(&regexbuf_comma);
+	regfree(&regexbuf_dash);
+	ast_free(channel_arg);
+
+	return channels_touched;
+}
+
+/*!
+ * \brief Set the BusyOut mode on a specific dahdi channel
+ *
+ * \param on Value of 0 for Disable, 1 for Enable
+ *
+ * \retval 0 on no change
+ * \retval 1 on change
+ * \retval 2 on queue of operation
+ * \retval -1 on failure
+ */
+static int dahdi_set_channel_busyout(struct dahdi_pvt *dahdi_chan, int on)
+{
+       int result = -1;
+
+       if (on) {
+               if (dahdi_chan->busyout) {
+                       ast_verb(1, "<DAHDI/%d> BusyOut already enabled\n", dahdi_chan->channel);
+                       return 0;
+               }
+
+               if (dahdi_chan->owner) {
+                       pthread_t busyout_trying_threadid;
+
+                        if (dahdi_chan->busyout_queued) {
+                               ast_log(LOG_WARNING, "Channel DAHDI/%d already has a busyout queued\n", dahdi_chan->channel);
+                               return -1;
+                       }
+
+                       ast_log(LOG_NOTICE, "Channel DAHDI/%d already has a call, queueing busyout\n", dahdi_chan->channel);
+                       dahdi_chan->busyout_queued = 1;
+                       result = ast_pthread_create_detached(&busyout_trying_threadid, NULL, dahdi_set_channel_busyout_on_thread, dahdi_chan);
+                       if (result) {
+                               ast_log(LOG_WARNING, "Unable to start busyout queue thread on channel DAHDI/%d\n", dahdi_chan->channel);
+                               return -1;
+                       }
+
+                       return 2;
+               }
+
+               ast_mutex_lock(&dahdi_chan->lock);
+               dahdi_busyout_start(dahdi_chan);
+               ast_mutex_unlock(&dahdi_chan->lock);
+
+               return 1;
+       }
+
+       /* off */
+        if (dahdi_chan->busyout_queued) {
+               dahdi_chan->busyout_queued = 0;
+               ast_log(LOG_WARNING, "Channel DAHDI/%d busyout queue cancelled\n", dahdi_chan->channel);
+               return 1;
+       }
+
+       if (!dahdi_chan->busyout) {
+               ast_verb(1, "<DAHDI/%d> BusyOut already disabled\n", dahdi_chan->channel);
+               return 0;
+       }
+
+       ast_mutex_lock(&dahdi_chan->lock);
+
+       dahdi_chan->busyout_queued = 0;
+       dahdi_chan->busydetect = dahdi_chan->_busydetect;
+       dahdi_chan->busyout    = 0;
+
+       ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_NOT_CACHABLE, "DAHDI/%d/busyout", dahdi_chan->channel);
+
+       if (dahdi_chan->owner) {
+               ast_hangup(dahdi_chan->owner);
+               dahdi_set_hook(dahdi_chan->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
+               dahdi_fake_event(dahdi_chan, HANGUP);
+       }
+
+        /* Clear pending Ring/Answered from our busyout call */
+        dahdi_get_event(dahdi_chan->subs[SUB_REAL].dfd);
+
+       ast_mutex_unlock(&dahdi_chan->lock);
+
+       ast_verb(1, "<DAHDI/%d> Disabled BusyOut\n", dahdi_chan->channel);
+
+       return 1;
+}
 
 static int reload(void)
 {
diff --git a/channels/chan_dahdi.h b/channels/chan_dahdi.h
index de813f2..13db791 100644
--- a/channels/chan_dahdi.h
+++ b/channels/chan_dahdi.h
@@ -203,6 +203,21 @@
 	 * \note Set from the "busydetect" value read in from chan_dahdi.conf
 	 */
 	unsigned int busydetect:1;
+       /*!
+        * \brief TRUE if busyout mode is enabled as per configured (backup of busydetect setting for when in busyout mode).
+        * (Listens for the beep-beep busy pattern.)
+        * \note Set from the "busydetect" value read in from chan_dahdi.conf
+        */
+       unsigned int _busydetect:1;
+       /*!
+        * \brief TRUE if busyout mode is enabled.
+        */
+       unsigned int busyout:1;
+       /*!
+        * \brief TRUE if busyout mode is queued for enable.
+        * (If we have a call in progress, we will keep trying to enable busyout until the call is done)
+        */
+       unsigned int busyout_queued:1;
 	/*!
 	 * \brief TRUE if call return is enabled.
 	 * (*69, if your dialplan doesn't catch this first)

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/19264
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Change-Id: Ib75c87c554bb18b8f65be73b4474474e7e1877b7
Gerrit-Change-Number: 19264
Gerrit-PatchSet: 1
Gerrit-Owner: Mark Murawski <markm at intellasoft.net>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20220915/69060869/attachment-0001.html>


More information about the asterisk-code-review mailing list