<p>N A has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/18356">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">features: Add transfer initiation options.<br><br>Adds additional control options over the transfer<br>feature functionality to give users more control<br>in how the transfer feature sounds and works.<br><br>The "transfer" sound that plays when a transfer is<br>initiated can now be customized by the user in<br>features.conf, just as with the other transfer sounds.<br><br>Secondly, the user can now specify the transfer extension<br>in advance by using the TRANSFER_EXTEN variable. If<br>a valid extension is contained in this variable, the call<br>will automatically be transferred to this destination.<br>Otherwise, it will fall back to collecting the extension<br>from the user as is always done now.<br><br>ASTERISK-29899 #close<br><br>Change-Id: Ibff309caa459a2b958706f2ed0ca393b1ef502e3<br>---<br>M configs/samples/features.conf.sample<br>A doc/CHANGES-staging/transfer.txt<br>M include/asterisk/features_config.h<br>M main/bridge_basic.c<br>M main/features_config.c<br>5 files changed, 83 insertions(+), 17 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/56/18356/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/configs/samples/features.conf.sample b/configs/samples/features.conf.sample</span><br><span>index afdcf5a..05b514e 100644</span><br><span>--- a/configs/samples/features.conf.sample</span><br><span>+++ b/configs/samples/features.conf.sample</span><br><span>@@ -6,7 +6,11 @@</span><br><span> </span><br><span> [general]</span><br><span> ;transferdigittimeout => 3 ; Number of seconds to wait between digits when transferring a call</span><br><span style="color: hsl(0, 100%, 40%);">- ; (default is 3 seconds)</span><br><span style="color: hsl(120, 100%, 40%);">+ ; (default is 3 seconds). If the TRANSFER_EXTEN dialplan variable has been set</span><br><span style="color: hsl(120, 100%, 40%);">+ ; on the channel of the user that is invoking the transfer feature, then</span><br><span style="color: hsl(120, 100%, 40%);">+ ; this option is not used as the user is transferred directly to the extension</span><br><span style="color: hsl(120, 100%, 40%);">+ ; specified by TRANSFER_EXTEN (the transfer context remains the context specified</span><br><span style="color: hsl(120, 100%, 40%);">+ ; by TRANSFER_CONTEXT, if set, and otherwise the default context).</span><br><span> ;xfersound = beep ; to indicate an attended transfer is complete</span><br><span> ;xferfailsound = beeperr ; to indicate a failed transfer</span><br><span> ;pickupexten = *8 ; Configure the pickup extension. (default is *8)</span><br><span>@@ -26,12 +30,13 @@</span><br><span> ; By default, this is 2.</span><br><span> ;transferdialattempts = 3 ; Number of times that a transferer may attempt to dial an extension before</span><br><span> ; being kicked back to the original call.</span><br><span style="color: hsl(120, 100%, 40%);">+;transferannouncesound = beep ; Sound to play to a transferer to indicate transfer process has begun. If empty, no sound will be played.</span><br><span> ;transferretrysound = beep ; Sound to play when a transferer fails to dial a valid extension.</span><br><span> ;transferinvalidsound = beeperr ; Sound to play when a transferer fails to dial a valid extension and is out of retries.</span><br><span> ;atxferabort = *1 ; cancel the attended transfer</span><br><span> ;atxfercomplete = *2 ; complete the attended transfer, dropping out of the call</span><br><span> ;atxferthreeway = *3 ; complete the attended transfer, but stay in the call. This will turn the call into a multi-party bridge</span><br><span style="color: hsl(0, 100%, 40%);">-;atxferswap = *4 ; swap to the other party. Once an attended transfer has begun, this options may be used multiple times</span><br><span style="color: hsl(120, 100%, 40%);">+;atxferswap = *4 ; swap to the other party. Once an attended transfer has begun, this option may be used multiple times</span><br><span> </span><br><span> ; Note that the DTMF features listed below only work when two channels have answered and are bridged together.</span><br><span> ; They can not be used while the remote party is ringing or in progress. If you require this feature you can use</span><br><span>diff --git a/doc/CHANGES-staging/transfer.txt b/doc/CHANGES-staging/transfer.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..962272f</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/transfer.txt</span><br><span>@@ -0,0 +1,14 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: Transfer feature</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+The following capabilities have been added to the</span><br><span style="color: hsl(120, 100%, 40%);">+transfer feature:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+- The transfer initiation announcement prompt can</span><br><span style="color: hsl(120, 100%, 40%);">+now be customized in features.conf.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+- The TRANSFER_EXTEN variable now can be set on the</span><br><span style="color: hsl(120, 100%, 40%);">+transferer's channel in order to allow the transfer</span><br><span style="color: hsl(120, 100%, 40%);">+function to automatically attempt to go to the extension</span><br><span style="color: hsl(120, 100%, 40%);">+contained in this variable, if it exists. The transfer</span><br><span style="color: hsl(120, 100%, 40%);">+context behavior is not changed (TRANSFER_CONTEXT is used</span><br><span style="color: hsl(120, 100%, 40%);">+if it exists; otherwise the default context is used).</span><br><span>diff --git a/include/asterisk/features_config.h b/include/asterisk/features_config.h</span><br><span>index 5253369..336454b 100644</span><br><span>--- a/include/asterisk/features_config.h</span><br><span>+++ b/include/asterisk/features_config.h</span><br><span>@@ -72,6 +72,8 @@</span><br><span> AST_STRING_FIELD(transferretrysound);</span><br><span> /*! Sound played when an invalid extension is dialed, and the transferer is being returned to the call. */</span><br><span> AST_STRING_FIELD(transferinvalidsound);</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Sound to play to announce the transfer process has started. */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_STRING_FIELD(transferannouncesound);</span><br><span> );</span><br><span> /*! Seconds allowed between digit presses when dialing transfer destination */</span><br><span> unsigned int transferdigittimeout;</span><br><span>diff --git a/main/bridge_basic.c b/main/bridge_basic.c</span><br><span>index df21195..e2099ba 100644</span><br><span>--- a/main/bridge_basic.c</span><br><span>+++ b/main/bridge_basic.c</span><br><span>@@ -1398,6 +1398,27 @@</span><br><span> }</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Determine the transfer extension to use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param transferer Channel initiating the transfer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param extension User supplied extension if available. May be NULL.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The extension to use for the transfer.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static const char *get_transfer_exten(struct ast_channel *transferer, const char *exten)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(exten)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return exten;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ exten = pbx_builtin_getvar_helper(transferer, "TRANSFER_EXTEN");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(exten)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return exten;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return ""; /* empty default, to get transfer extension from user now */</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span> * \brief Allocate and initialize attended transfer properties</span><br><span> *</span><br><span> * \param transferer The channel performing the attended transfer</span><br><span>@@ -1452,6 +1473,7 @@</span><br><span> props->atxfernoanswertimeout = xfer_cfg->atxfernoanswertimeout;</span><br><span> props->atxferloopdelay = xfer_cfg->atxferloopdelay;</span><br><span> ast_string_field_set(props, context, get_transfer_context(transferer, context));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_string_field_set(props, exten, get_transfer_exten(transferer, NULL));</span><br><span> ast_string_field_set(props, xfersound, xfer_cfg->xfersound);</span><br><span> ao2_ref(xfer_cfg, -1);</span><br><span> </span><br><span>@@ -3155,16 +3177,26 @@</span><br><span> * \retval 0 on success</span><br><span> * \retval -1 on failure</span><br><span> */</span><br><span style="color: hsl(0, 100%, 40%);">-static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len, const char *context)</span><br><span style="color: hsl(120, 100%, 40%);">+static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len, const char *context, const char *extenoverride)</span><br><span> {</span><br><span> int res;</span><br><span> int digit_timeout;</span><br><span> int attempts = 0;</span><br><span> int max_attempts;</span><br><span> struct ast_features_xfer_config *xfer_cfg;</span><br><span style="color: hsl(0, 100%, 40%);">- char *retry_sound;</span><br><span style="color: hsl(0, 100%, 40%);">- char *invalid_sound;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *announce_sound, *retry_sound, *invalid_sound;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(extenoverride)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ int extenres = ast_exists_extension(chan, context, extenoverride, 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)) ? 1 : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (extenres) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_copy_string(exten, extenoverride, exten_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_verb(3, "Transfering call to '%s@%s'", exten, context);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "Override extension '%s' does not exist in context '%s'\n", extenoverride, context);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* since we didn't get a valid extension from the channel, fall back and grab it from the user as usual now */</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> ast_channel_lock(chan);</span><br><span> xfer_cfg = ast_get_chan_features_xfer_config(chan);</span><br><span> if (!xfer_cfg) {</span><br><span>@@ -3175,21 +3207,24 @@</span><br><span> }</span><br><span> digit_timeout = xfer_cfg->transferdigittimeout * 1000;</span><br><span> max_attempts = xfer_cfg->transferdialattempts;</span><br><span style="color: hsl(120, 100%, 40%);">+ announce_sound = ast_strdupa(xfer_cfg->transferannouncesound);</span><br><span> retry_sound = ast_strdupa(xfer_cfg->transferretrysound);</span><br><span> invalid_sound = ast_strdupa(xfer_cfg->transferinvalidsound);</span><br><span> ao2_ref(xfer_cfg, -1);</span><br><span> ast_channel_unlock(chan);</span><br><span> </span><br><span> /* Play the simple "transfer" prompt out and wait */</span><br><span style="color: hsl(0, 100%, 40%);">- res = ast_stream_and_wait(chan, "pbx-transfer", AST_DIGIT_ANY);</span><br><span style="color: hsl(0, 100%, 40%);">- ast_stopstream(chan);</span><br><span style="color: hsl(0, 100%, 40%);">- if (res < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* Hangup or error */</span><br><span style="color: hsl(0, 100%, 40%);">- return -1;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- if (res) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* Store the DTMF digit that interrupted playback of the file. */</span><br><span style="color: hsl(0, 100%, 40%);">- exten[0] = res;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(announce_sound)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ res = ast_stream_and_wait(chan, announce_sound, AST_DIGIT_ANY);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_stopstream(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Hangup or error */</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Store the DTMF digit that interrupted playback of the file. */</span><br><span style="color: hsl(120, 100%, 40%);">+ exten[0] = res;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> </span><br><span> /* Drop to dialtone so they can enter the extension they want to transfer to */</span><br><span>@@ -3348,7 +3383,7 @@</span><br><span> ast_bridge_channel_write_hold(bridge_channel, NULL);</span><br><span> </span><br><span> /* Grab the extension to transfer to */</span><br><span style="color: hsl(0, 100%, 40%);">- if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), props->context)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), props->context, props->exten)) {</span><br><span> /*</span><br><span> * This is a normal exit for when the user fails</span><br><span> * to specify a valid transfer target. e.g., The user</span><br><span>@@ -3470,7 +3505,7 @@</span><br><span> {</span><br><span> char xfer_exten[AST_MAX_EXTENSION] = "";</span><br><span> struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;</span><br><span style="color: hsl(0, 100%, 40%);">- const char *xfer_context;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *xfer_context, *xfer_exten_override;</span><br><span> char *goto_on_blindxfer;</span><br><span> </span><br><span> ast_verb(3, "Channel %s: Started DTMF blind transfer.\n",</span><br><span>@@ -3481,12 +3516,13 @@</span><br><span> ast_channel_lock(bridge_channel->chan);</span><br><span> xfer_context = ast_strdupa(get_transfer_context(bridge_channel->chan,</span><br><span> blind_transfer ? blind_transfer->context : NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+ xfer_exten_override = ast_strdupa(get_transfer_exten(bridge_channel->chan, NULL));</span><br><span> goto_on_blindxfer = ast_strdupa(S_OR(pbx_builtin_getvar_helper(bridge_channel->chan,</span><br><span> "GOTO_ON_BLINDXFR"), ""));</span><br><span> ast_channel_unlock(bridge_channel->chan);</span><br><span> </span><br><span> /* Grab the extension to transfer to */</span><br><span style="color: hsl(0, 100%, 40%);">- if (grab_transfer(bridge_channel->chan, xfer_exten, sizeof(xfer_exten), xfer_context)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (grab_transfer(bridge_channel->chan, xfer_exten, sizeof(xfer_exten), xfer_context, xfer_exten_override)) {</span><br><span> ast_bridge_channel_write_unhold(bridge_channel);</span><br><span> return 0;</span><br><span> }</span><br><span>diff --git a/main/features_config.c b/main/features_config.c</span><br><span>index 50ca69b..d91d97f 100644</span><br><span>--- a/main/features_config.c</span><br><span>+++ b/main/features_config.c</span><br><span>@@ -143,6 +143,9 @@</span><br><span> <configOption name="transferinvalidsound" default="privacy-incorrect"></span><br><span> <synopsis>Sound that is played when an incorrect extension is dialed and the transferer has no attempts remaining.</synopsis></span><br><span> </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="transferannouncesound" default="pbx-transfer"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>Sound that is played to the transferer when a transfer is initiated. If empty, no sound will be played.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span> </configObject></span><br><span> <configObject name="featuremap"></span><br><span> <synopsis>DTMF options that can be triggered during bridged calls</synopsis></span><br><span>@@ -320,6 +323,7 @@</span><br><span> <enum name="transferdialattempts"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferdialattempts']/synopsis/text())" /></para></enum></span><br><span> <enum name="transferretrysound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferretrysound']/synopsis/text())" /></para></enum></span><br><span> <enum name="transferinvalidsound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferinvalidsound']/synopsis/text())" /></para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+ <enum name="transferannouncesound"><para><xi:include xpointer="xpointer(/docs/configInfo[@name='features']/configFile[@name='features.conf']/configObject[@name='globals']/configOption[@name='transferannouncesound']/synopsis/text())" /></para></enum></span><br><span> </enumlist></span><br><span> </parameter></span><br><span> </syntax></span><br><span>@@ -383,6 +387,7 @@</span><br><span> #define DEFAULT_TRANSFER_DIAL_ATTEMPTS 3</span><br><span> #define DEFAULT_TRANSFER_RETRY_SOUND "pbx-invalid"</span><br><span> #define DEFAULT_TRANSFER_INVALID_SOUND "privacy-incorrect"</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEFAULT_TRANSFER_ANNOUNCE_SOUND "pbx-transfer"</span><br><span> </span><br><span> /*! Default pickup options */</span><br><span> #define DEFAULT_PICKUPEXTEN "*8"</span><br><span>@@ -906,6 +911,8 @@</span><br><span> ast_string_field_set(xfer, transferretrysound, value);</span><br><span> } else if (!strcasecmp(name, "transferinvalidsound")) {</span><br><span> ast_string_field_set(xfer, transferinvalidsound, value);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!strcasecmp(name, "transferannouncesound")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_string_field_set(xfer, transferannouncesound, value);</span><br><span> } else {</span><br><span> /* Unrecognized option */</span><br><span> res = -1;</span><br><span>@@ -1797,6 +1804,8 @@</span><br><span> DEFAULT_TRANSFER_RETRY_SOUND, xfer_handler, 0);</span><br><span> aco_option_register_custom(&cfg_info, "transferinvalidsound", ACO_EXACT, global_options,</span><br><span> DEFAULT_TRANSFER_INVALID_SOUND, xfer_handler, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ aco_option_register_custom(&cfg_info, "transferannouncesound", ACO_EXACT, global_options,</span><br><span style="color: hsl(120, 100%, 40%);">+ DEFAULT_TRANSFER_ANNOUNCE_SOUND, xfer_handler, 0);</span><br><span> </span><br><span> aco_option_register_custom(&cfg_info, "pickupexten", ACO_EXACT, global_options,</span><br><span> DEFAULT_PICKUPEXTEN, pickup_handler, 0);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/18356">change 18356</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/18356"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-Change-Id: Ibff309caa459a2b958706f2ed0ca393b1ef502e3 </div>
<div style="display:none"> Gerrit-Change-Number: 18356 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: N A <mail@interlinked.x10host.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>